pbeets
rithmic-rs
Rust

Connect to RithmicAPI using Rust for Algorithmic Trading

Last updated Jul 2, 2026
41
Stars
13
Forks
0
Issues
0
Stars/day
Attention Score
74
Language breakdown
Rust 100.0%
Files click to expand
README

Rust Rithmic R | Protocol API client

Crates.io docs.rs CI License

Official Rithmic API

Unofficial rust client for connecting to Rithmic's R | Protocol API.

Quick Start

Add to your Cargo.toml:

[dependencies]
rithmic-rs = "2.0.0"

Set your environment variables:

RITHMICAPPNAME=yourappname
RITHMICAPPVERSION=1

RITHMICDEMOUSER=your_username RITHMICDEMOPW=your_password RITHMICDEMOURL=<providedbyrithmic> RITHMICDEMOALTURL=<providedby_rithmic>

Required for order and PnL requests

RITHMICDEMOACCOUNTID=youraccount_id RITHMICDEMOFCMID=yourfcm_id RITHMICDEMOIBID=yourib_id

See examples/.env.blank for Live

RithmicConfig contains connection and login details. RithmicAccount is separate and identifies which trading account to use for order and PnL requests. Login is user-scoped; account fields are sent with account-scoped requests, not during the initial sign-in.

Stream live market data:

use rithmic_rs::{RithmicConfig, RithmicEnv, ConnectStrategy, RithmicTickerPlant};

#[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { let config = RithmicConfig::from_env(RithmicEnv::Demo)?; // for live RithmicEnv::Live let plant = RithmicTickerPlant::connect(&config, ConnectStrategy::Retry).await?; let mut handle = plant.get_handle();

handle.login().await?; handle.subscribe("ESM6", "CME").await?; // Update to current front-month ES contract

while let Ok(update) = handle.subscription_receiver.recv().await { println!("{:?}", update.message); }

Ok(()) }

See examples/ for more usage patterns including reconnection handling and historical data loading.

Architecture

This library uses the actor pattern where each Rithmic service runs independently in its own thread. All communication happens through tokio channels.

  • RithmicTickerPlant - Real-time market data (trades, quotes, order book)
  • RithmicOrderPlant - Order entry and management
  • RithmicHistoryPlant - Historical tick and bar data
  • RithmicPnlPlant - Position and P&L tracking

Ticker Plant

// Subscribe to real-time quotes
handle.subscribe("ESM6", "CME").await?;

// Unsubscribe when done handle.unsubscribe("ESM6", "CME").await?;

// Additional market data subscriptions handle.subscribeinstrumentstatus("ESM6", "CME").await?; handle.subscribeopeninterest("ESM6", "CME").await?; handle.subscribesessionprices("ESM6", "CME").await?; handle.subscribeorderprice_limits("ESM6", "CME").await?;

// Symbol discovery let symbols = handle.search_symbols("ES", Some("CME"), None, None, None).await?; let frontmonth = handle.getfrontmonthcontract("ES", "CME", false).await?;

Order Plant

use rithmic_rs::{
    ConnectStrategy, NewOrderPriceType, NewOrderTransactionType, RithmicAccount,
    RithmicConfig, RithmicEnv, RithmicOrder, RithmicOrderPlant,
};

let config = RithmicConfig::from_env(RithmicEnv::Demo)?; let account = RithmicAccount::from_env(RithmicEnv::Demo)?; let plant = RithmicOrderPlant::connect(&config, ConnectStrategy::Retry).await?; let mut handle = plant.get_handle(&account); handle.login().await?;

// Place orders using the RithmicOrder API let order = RithmicOrder { symbol: "ESM6".to_string(), exchange: "CME".to_string(), quantity: 1, price: 5000.0, transaction_type: NewOrderTransactionType::Buy, price_type: NewOrderPriceType::Limit, usertag: "my-order".tostring(), ..Default::default() }; handle.place_order(order).await?;

// Bracket orders, OCO orders, advanced bracket orders handle.placebracketorder(...).await?; handle.placeadvancedbracketorder(advancedorder).await?;

// Manage positions handle.cancelorder(orderid).await?; handle.exit_position("ESM6", "CME").await?;

For multi-account workflows, create one [RithmicAccount] per account and call get_handle(&account) for each handle you need.

History Plant

// Load historical data (bartype, period, starttime, end_time as i32 unix seconds)
let bars = handle.loadtimebars("ESM6", "CME", BarType::MinuteBar, 5, start, end).await?;
let ticks = handle.load_ticks("ESM6", "CME", start, end).await?;

// Load N-tick bars (e.g., 5-tick bars) let tickbars = handle.loadtick_bars("ESM6", "CME", 5, start, end).await?;

PnL Plant

use rithmic_rs::{
    ConnectStrategy, RithmicAccount, RithmicConfig, RithmicEnv, RithmicPnlPlant,
};

let config = RithmicConfig::from_env(RithmicEnv::Demo)?; let account = RithmicAccount::from_env(RithmicEnv::Demo)?; let plant = RithmicPnlPlant::connect(&config, ConnectStrategy::Retry).await?; let mut handle = plant.get_handle(&account); handle.login().await?;

// Monitor P&L handle.subscribepnlupdates().await?; let snapshot = handle.pnlpositionsnapshots().await?;

Error Handling

All plant handle methods return Result<_, RithmicError> with typed variants you can match on for recovery decisions:

use rithmic_rs::RithmicError;

match handle.subscribe("ESM6", "CME").await { Ok(resp) => { / success / } Err(RithmicError::ConnectionClosed | RithmicError::SendFailed) => { handle.abort(); // reconnect — see examples/reconnect.rs } Err(RithmicError::InvalidArgument(msg)) => eprintln!("Bad argument: {}", msg), Err(RithmicError::RequestRejected(err)) => { eprintln!( "Server rejected: code={} msg={}", err.code.asderef().unwrapor("?"), err.message.asderef().unwrapor(""), ); } Err(RithmicError::ProtocolError(msg)) => eprintln!("Protocol error: {}", msg), Err(e) => eprintln!("{}", e), }

When inspecting a RithmicResponse directly (for example, entries from a subscription broadcast), match on response.error — it is Option<RithmicError>. Use [RithmicError::isconnectionissue] to distinguish transport failures from protocol rejections. The raw rp_code payload is also accessible:

  • response.rp_code() -> Option<&[String]> — full raw payload as received.
  • response.rpcodenum() -> Option<&str> — numeric code (first element).
  • response.rpcodetext() -> Option<&str> — human message (second element).
RithmicError implements std::error::Error, so ? works in functions returning Box<dyn Error>.

Connection Strategies

Three strategies for initial connection:

  • Simple: Single attempt, fast-fail
  • Retry: Exponential backoff, capped at 60 seconds (recommended default)
  • AlternateWithRetry: Alternates between primary and alt URLs

Reconnection

If you need to handle disconnections and automatically reconnect, you must implement your own reconnection loop. See examples/reconnect.rs for a complete example that tracks subscriptions and re-subscribes after reconnect.

Upgrading

See CHANGELOG.md for version history.

Contribution

Contributions encouraged and welcomed!

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as below, without any additional terms or conditions.

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option.

🔗 More in this category

© 2026 GitRepoTrend · pbeets/rithmic-rs · Updated daily from GitHub