Skip to content

Latest commit

 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OpenAlgo Rust SDK

A Rust wrapper for the OpenAlgo API with WebSocket support for real-time market data streaming.

Installation

Add this to your Cargo.toml:

[dependencies]
openalgo = "1.0.5"
tokio = { version = "1", features = ["full"] }

Or install using cargo:

cargo add openalgo tokio --features tokio/full

Quick Start

use openalgo::OpenAlgo;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Simple initialization with just API key
    let client = OpenAlgo::new("your_api_key");

    // Get quotes
    let quotes = client.quotes("RELIANCE", "NSE").await?;
    println!("{:?}", quotes);

    // Place a simple market order
    let order = client.place_order("Strategy1", "RELIANCE", "BUY", "NSE", "MARKET", "MIS", "1").await?;
    println!("{:?}", order);

    Ok(())
}

Configuration

// Simple initialization (uses default host and WebSocket URL)
let client = OpenAlgo::new("your_api_key");

// Custom configuration
let client = OpenAlgo::with_config(
    "your_api_key",
    "http://127.0.0.1:5000",    // Host
    "v1",                        // API Version
    "ws://127.0.0.1:8765",      // WebSocket URL
);

Order API

Place Order

Place a simple market order. disclosed_quantity is optional (Option<&str>).

let order = client.place_order(
    "Strategy1",      // strategy
    "RELIANCE",       // symbol
    "BUY",            // action (BUY/SELL)
    "NSE",            // exchange (NSE/BSE/NFO/MCX/CDS/BFO)
    "MARKET",         // pricetype (MARKET/LIMIT/SL/SL-M)
    "MIS",            // product (CNC/NRML/MIS)
    "1",              // quantity
    None,             // disclosed_quantity: Option<&str>
).await?;

Response:

{
    "status": "success",
    "orderid": "1234567890"
}

Place Limit Order

Place a limit order with price. disclosed_quantity is optional (Option<&str>).

let order = client.place_limit_order(
    "Strategy1",      // strategy
    "RELIANCE",       // symbol
    "BUY",            // action
    "NSE",            // exchange
    "MIS",            // product
    "1",              // quantity
    "2500.00",        // price
    None,             // disclosed_quantity: Option<&str>
).await?;

Place Stop-Loss Order

Place a stop-loss order with trigger price. disclosed_quantity is optional (Option<&str>).

let order = client.place_sl_order(
    "Strategy1",      // strategy
    "RELIANCE",       // symbol
    "BUY",            // action
    "NSE",            // exchange
    "MIS",            // product
    "1",              // quantity
    "2500.00",        // price
    "2490.00",        // trigger_price
    None,             // disclosed_quantity: Option<&str>
).await?;

Place Smart Order

Place an order with position sizing logic.

let order = client.place_smart_order(
    "Strategy1",      // strategy
    "RELIANCE",       // symbol
    "BUY",            // action
    "NSE",            // exchange
    "MARKET",         // pricetype
    "MIS",            // product
    "1",              // quantity
    "5",              // position_size
).await?;

Options Order

Place an options order with automatic strike selection.

Note: there is no splitsize parameter on this endpoint (an earlier version of this SDK mistakenly required one — the real OpenAlgo optionsorder endpoint has no such field). expiry_date is optional (resolvable when underlying already embeds an expiry, e.g. "NIFTY28OCT25FUT"), and strike_int is an optional, deprecated parameter kept only for parity with the Python SDK. Use OrderAPI::split_order separately if you need order splitting.

use std::collections::HashMap;

let order = client.options_order(
    "Strategy1",      // strategy
    "NIFTY",          // underlying
    "NFO",            // exchange
    "0",              // offset (0=ATM, 1=OTM1, -1=ITM1)
    "CE",             // option_type (CE/PE)
    "BUY",            // action
    "50",             // quantity
    "MARKET",         // pricetype
    "MIS",            // product
    Some("241226"),   // expiry_date (YYMMDD), optional
    None,             // strike_int (deprecated), optional
    None,             // extra: Option<HashMap<String, serde_json::Value>> forwarded verbatim
).await?;

// LIMIT order using `extra` to forward broker-specific / order-specific fields
// (mirrors Python's **kwargs: price, trigger_price, disclosed_quantity, ...)
let mut extra = HashMap::new();
extra.insert("price".to_string(), serde_json::json!("50.0"));
let limit_order = client.options_order(
    "Strategy1", "NIFTY", "NFO", "0", "CE", "BUY", "50", "LIMIT", "MIS",
    Some("241226"), None, Some(extra),
).await?;

Response:

{
    "status": "success",
    "orderid": "1234567890",
    "symbol": "NIFTY24DEC24000CE",
    "exchange": "NFO",
    "offset": "0",
    "option_type": "CE",
    "underlying": "NIFTY",
    "underlying_ltp": 24000.50,
    "mode": "live"
}

Options Multi-Order

Place multi-leg options orders (spreads, straddles, etc.).

use openalgo::OptionsLeg;

// Bull Call Spread
let legs = vec![
    OptionsLeg::new("0", "CE", "BUY", "50"),   // Buy ATM Call
    OptionsLeg::new("2", "CE", "SELL", "50"),  // Sell OTM Call
];

let order = client.options_multi_order(
    "Strategy1",      // strategy
    "NIFTY",          // underlying
    "NFO",            // exchange
    "241226",         // expiry_date
    legs,
).await?;

Response:

{
    "status": "success",
    "underlying": "NIFTY",
    "underlying_ltp": 24000.50,
    "results": [
        {"leg": 1, "status": "success", "orderid": "1234567890", "symbol": "NIFTY24DEC24000CE"},
        {"leg": 2, "status": "success", "orderid": "1234567891", "symbol": "NIFTY24DEC24100CE"}
    ]
}

Basket Order

Place multiple orders at once.

use openalgo::BasketOrderItem;

let orders = vec![
    BasketOrderItem::new("RELIANCE", "NSE", "BUY", 1, "MARKET", "MIS"),
    BasketOrderItem::new("TCS", "NSE", "BUY", 1, "MARKET", "MIS"),
];

let result = client.basket_order("Strategy1", orders).await?;

Response:

{
    "status": "success",
    "results": [
        {"symbol": "RELIANCE", "status": "success", "orderid": "1234567890"},
        {"symbol": "TCS", "status": "success", "orderid": "1234567891"}
    ]
}

Split Order

Split a large order into smaller chunks.

let result = client.split_order(
    "Strategy1",      // strategy
    "RELIANCE",       // symbol
    "BUY",            // action
    "NSE",            // exchange
    100,              // total quantity (i32)
    25,               // splitsize (i32)
    "MARKET",         // pricetype
    "MIS",            // product
).await?;

Modify Order

Modify an existing order. disclosed_quantity, trigger_price, and extra (broker-specific kwargs forwarded verbatim) are optional.

let result = client.modify_order(
    "1234567890",     // orderid
    "Strategy1",      // strategy
    "RELIANCE",       // symbol
    "BUY",            // action
    "NSE",            // exchange
    "LIMIT",          // pricetype
    "MIS",            // product
    "1",              // quantity
    "2550.00",        // price
    None,             // disclosed_quantity: Option<&str>
    None,             // trigger_price: Option<&str>
    None,             // extra: Option<HashMap<String, serde_json::Value>>
).await?;

// With disclosed quantity and trigger price
let result = client.modify_order(
    "1234567890", "Strategy1", "RELIANCE", "BUY", "NSE", "SL", "MIS", "1", "2550.00",
    Some("200"), Some("2545.00"), None,
).await?;

Cancel Order

Cancel a specific order.

let result = client.cancel_order("1234567890", "Strategy1").await?;

Cancel All Orders

Cancel all open orders for a strategy.

let result = client.cancel_all_order("Strategy1").await?;

Close Position

Close all positions for a strategy.

let result = client.close_position("Strategy1").await?;

Order Status

Get the status of an order.

let status = client.order_status("1234567890", "Strategy1").await?;

Open Position

Get current open position for a symbol.

let position = client.open_position("Strategy1", "RELIANCE", "NSE", "MIS").await?;

Data API

Quotes

Get real-time quotes for a symbol.

let quotes = client.quotes("RELIANCE", "NSE").await?;

Response:

{
    "status": "success",
    "data": {
        "ltp": 2500.50,
        "open": 2480.00,
        "high": 2510.00,
        "low": 2475.00,
        "prev_close": 2485.00,
        "volume": 1234567,
        "bid": 2500.00,
        "ask": 2500.50,
        "oi": 0
    }
}

Multi Quotes

Get quotes for multiple symbols.

let quotes = client.multi_quotes(&[
    ("RELIANCE", "NSE"),
    ("TCS", "NSE"),
    ("INFY", "NSE"),
]).await?;

Market Depth

Get order book depth.

let depth = client.depth("RELIANCE", "NSE").await?;

History

Get historical OHLCV data.

// Simple form - latest data
let history = client.history("RELIANCE", "NSE", "5m").await?;

// With date range
let history = client.history_range("RELIANCE", "NSE", "5m", "2024-01-01", "2024-01-31").await?;

Intervals

Get available intervals.

let intervals = client.intervals().await?;

// Legacy alias (mirrors Python's `interval()`)
let intervals = client.interval().await?;

Symbol

Get symbol information.

let info = client.symbol("RELIANCE", "NSE").await?;

Search

Search for symbols. exchange is optional — pass None to search across all exchanges.

let results = client.search("RELI", Some("NSE"), None).await?;

// Search across all exchanges
let results = client.search("RELI", None, None).await?;

Expiry

Get expiry dates.

let expiries = client.expiry("NIFTY", "NFO", "OPT").await?;

Option Chain

Get option chain data.

let chain = client.option_chain("NIFTY", "NFO", "241226").await?;

Option Symbol

Get option symbol details by underlying + offset, without placing an order. expiry_date is optional (resolvable when underlying already embeds an expiry, e.g. "NIFTY28OCT25FUT"); strategy and strike_int are optional, deprecated parameters kept only for parity with the Python SDK.

let symbol = client.option_symbol(
    "NIFTY", "NFO", "0", "CE",
    Some("241226"),   // expiry_date, optional
    None,             // strategy (deprecated), optional
    None,             // strike_int (deprecated), optional
    None,             // extra kwargs, optional
).await?;

Synthetic Future

Get synthetic future price.

let future = client.synthetic_future("NIFTY", "NFO", "241226").await?;

Option Greeks

Get option Greeks (Delta, Gamma, Theta, Vega, Rho) and implied volatility. Only symbol/exchange are required — everything else is optional and auto-detected or defaulted server-side (interest rate defaults to 0; the underlying is auto-detected; live prices are fetched unless forward_price is supplied).

let greeks = client.option_greeks(
    "NIFTY24DEC24000CE",
    "NFO",
    Some(6.5),        // interest_rate, optional
    None,             // forward_price, optional (skips underlying price fetch)
    Some("NIFTY"),    // underlying_symbol, optional (auto-detected otherwise)
    Some("NSE"),      // underlying_exchange, optional (auto-detected otherwise)
    None,             // expiry_time, optional (e.g. "19:00" for MCX)
    None,             // extra kwargs, optional
).await?;

// Simplest form — everything auto-detected
let greeks = client.option_greeks("NIFTY24DEC24000CE", "NFO", None, None, None, None, None, None).await?;

Instruments

Download instrument master data, with optional exchange filtering. Pass exchange: None to download instruments for all supported exchanges (NSE, BSE, NFO, BFO, MCX, CDS, BCD, NSE_INDEX, BSE_INDEX) combined into one response, mirroring Python's instruments(exchange=None).

let instruments = client.instruments(Some("NSE")).await?;

// Download all exchanges
let all_instruments = client.instruments(None).await?;

Account API

Funds

Get account funds.

let funds = client.funds().await?;

Response:

{
    "status": "success",
    "data": {
        "availablecash": "100000.00",
        "collateral": "50000.00",
        "m2mrealized": "1000.00",
        "m2munrealized": "-500.00",
        "utiliseddebits": "25000.00"
    }
}

Orderbook

Get all orders.

let orderbook = client.orderbook().await?;

Tradebook

Get all trades.

let tradebook = client.tradebook().await?;

Positionbook

Get all positions.

let positions = client.positionbook().await?;

Holdings

Get holdings.

let holdings = client.holdings().await?;

Margin

Get margin requirement for positions.

use openalgo::MarginPosition;

let positions = vec![
    MarginPosition::new("NIFTY24DEC24000CE", "NFO", "BUY", "MIS", "MARKET", "50"),
];
let margin = client.margin(positions).await?;

Utilities API

Holidays

Get market holidays. year is optional (2020-2050) — pass None to let the server default to the current year.

let holidays = client.holidays(Some(2024)).await?;

// Current year (server default)
let holidays = client.holidays(None).await?;

Timings

Get exchange timings for a date. date is optional — pass None to default client-side to today's date (YYYY-MM-DD, Asia/Kolkata), matching Python's datetime.now() default.

let timings = client.timings(Some("2024-12-25")).await?;

// Today's timings
let timings = client.timings(None).await?;

Telegram

Send a Telegram message.

let result = client.telegram("username", "Hello from OpenAlgo!").await?;

// Custom priority (1-10)
let result = client.telegram_priority("username", "Urgent alert!", 10).await?;

WhatsApp API

Send WhatsApp notifications through the OpenAlgo paired device. Requires the device to already be paired from the OpenAlgo web UI's /whatsapp page — pairing itself is intentionally not exposed via the API.

Send a WhatsApp Message

The simplest form sends a plain-text message to the paired device itself (self).

let result = client.whatsapp_message("Build #482 deployed. P&L: +1.2%").await?;

// To a single phone number (E.164 digits)
let result = client.whatsapp_to("919876543210", "Stop-loss hit on BANKNIFTY!").await?;

Response:

{
    "status": "success",
    "message": "Delivered to 1, failed 0",
    "data": { "sent": ["<self>"], "failed": [], "skipped": 0 }
}

Full Control (broadcast, image/document attachments, fire-and-forget)

For anything beyond a single self/phone text message — broadcasts (up to 5 recipients), username-based recipients, image/document attachments, or wait_for_delivery=false — use client.whatsapp.whatsapp(recipient, options) directly.

use openalgo::whatsapp::{WhatsAppRecipient, WhatsAppOptions};

// Small broadcast (max 5 numbers; anything beyond is dropped server-side)
let result = client.whatsapp.whatsapp(
    WhatsAppRecipient::Phones(vec!["919876543210".to_string(), "919812345678".to_string()]),
    WhatsAppOptions {
        message: Some("Server maintenance in 10 minutes".to_string()),
        ..Default::default()
    },
).await?;

// Send to a linked OpenAlgo username, with an image attachment
let result = client.whatsapp.whatsapp(
    WhatsAppRecipient::Username("alice".to_string()),
    WhatsAppOptions {
        message: Some("NIFTY end-of-day chart".to_string()),
        image: Some("/srv/charts/nifty_eod.png".to_string()),
        ..Default::default()
    },
).await?;

// Fire-and-forget (skip the delivery report) for time-critical alerts
let result = client.whatsapp.whatsapp(
    WhatsAppRecipient::SelfDevice,
    WhatsAppOptions { message: Some("Stop-loss hit!".to_string()), wait_for_delivery: Some(false), ..Default::default() },
).await?;

Analyzer API

Status

Get analyzer status.

let status = client.analyzer_status().await?;

Toggle

Toggle analyzer mode.

let result = client.analyzer_toggle(true).await?;

Strategy Webhook

Strategy is a standalone TradingView-style webhook poster — unlike every other API in this SDK, it is not part of OpenAlgo. It has no API key; instead it POSTs directly to a strategy's webhook URL ({host_url}/strategy/webhook/{webhook_id}). The strategy mode (LONG_ONLY, SHORT_ONLY, BOTH) is configured on the OpenAlgo server, not in the SDK call.

use openalgo::Strategy;

let strategy = Strategy::new("http://127.0.0.1:5000", "your-webhook-id");

// Simple signal
let result = strategy.strategy_order("RELIANCE", "BUY", None).await?;

// With an explicit position size (required for BOTH mode)
let result = strategy.strategy_order("NIFTY", "SELL", Some(50)).await?;

WebSocket API

Connect and Subscribe

use openalgo::{OpenAlgo, WsInstrument};
use openalgo::websocket::{WsSubscriber, WsData};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let client = OpenAlgo::new("your_api_key");
    let ws = client.websocket();

    // Connect
    let (cmd_tx, mut data_rx) = ws.connect().await?;
    let subscriber = WsSubscriber::new(cmd_tx);

    // Define instruments
    let instruments = vec![
        WsInstrument::new("NSE", "RELIANCE"),
        WsInstrument::new("NSE", "TCS"),
    ];

    // Subscribe to LTP
    subscriber.subscribe_ltp(instruments.clone()).await?;

    // Receive data
    while let Some(data) = data_rx.recv().await {
        match data {
            WsData::Ltp(ltp) => {
                println!("LTP: {} - {}",
                    ltp.symbol.unwrap_or_default(),
                    ltp.ltp.unwrap_or_default()
                );
            }
            WsData::Quote(quote) => {
                println!("Quote: {} - LTP: {}, High: {}, Low: {}",
                    quote.symbol.unwrap_or_default(),
                    quote.ltp.unwrap_or_default(),
                    quote.high.unwrap_or_default(),
                    quote.low.unwrap_or_default()
                );
            }
            WsData::Depth(depth) => {
                println!("Depth: {} - Bids: {:?}",
                    depth.symbol.unwrap_or_default(),
                    depth.bids
                );
            }
            _ => {}
        }
    }

    Ok(())
}

Subscription Modes

  • LTP Mode: Last traded price only
  • Quote Mode: OHLC + Volume data
  • Depth Mode: Full order book depth
// Subscribe to different modes
subscriber.subscribe_ltp(instruments.clone()).await?;
subscriber.subscribe_quote(instruments.clone()).await?;
subscriber.subscribe_depth(instruments.clone()).await?;

// Unsubscribe
subscriber.unsubscribe_ltp(instruments.clone()).await?;

// Disconnect
subscriber.disconnect().await?;

Snapshot Getters (get_ltp / get_quotes / get_depth)

Alongside the channel-based data_rx stream, OpenAlgoWebSocket keeps a local snapshot cache (keyed by "EXCHANGE:SYMBOL") that is updated as market_data messages arrive, mirroring Python FeedAPI's get_ltp() / get_quotes() / get_depth(). Call these any time on the same ws instance you connected with — no need to consume data_rx yourself just to read the latest values. Both exchange and symbol filters are optional; omit either (or both) to get everything cached so far.

// After ws.connect() and subscribing...

// Nested JSON: {"ltp": {"NSE": {"RELIANCE": {"timestamp": ..., "ltp": ...}}}}
let ltp_snapshot = ws.get_ltp(None, None);
let ltp_reliance = ws.get_ltp(Some("NSE"), Some("RELIANCE"));

// Nested JSON: {"quote": {"NSE": {"RELIANCE": {"open", "high", "low", "close", "ltp", "volume", ...}}}}
let quotes_snapshot = ws.get_quotes(Some("NSE"), None);

// Nested JSON: {"depth": {"NSE": {"RELIANCE": {"timestamp", "ltp", "buyBook": {"1": {...}, ..., "5": {...}}, "sellBook": {...}}}}}
let depth_snapshot = ws.get_depth(Some("NSE"), Some("RELIANCE"));

Running Examples

# Set your API key
export OPENALGO_API_KEY=your_api_key

# Run examples
cargo run --example place_order
cargo run --example options_order
cargo run --example quotes
cargo run --example account
cargo run --example websocket

Error Handling

use openalgo::client::OpenAlgoError;

match client.quotes("RELIANCE", "NSE").await {
    Ok(result) => println!("Success: {:?}", result),
    Err(OpenAlgoError::RequestError(e)) => println!("HTTP Error: {}", e),
    Err(OpenAlgoError::ApiError(msg)) => println!("API Error: {}", msg),
    Err(OpenAlgoError::JsonError(e)) => println!("JSON Error: {}", e),
    Err(e) => println!("Other Error: {}", e),
}

License

MIT License

Links

About

No description, website, or topics provided.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages