ostium-rust-sdk 0.1.0

Rust SDK for interacting with the Ostium trading platform on Arbitrum
Documentation
//! Advanced Order Types Example for the Ostium Rust SDK
//!
//! This example demonstrates how to:
//! - Place limit orders
//! - Place stop orders
//! - Update existing orders
//! - Cancel orders
//! - Validate order prices
//!
//! ⚠️  WARNING: This example uses MAINNET with REAL MONEY!
//! Use a secure private key and start with small amounts for testing.

use ostium_rust_sdk::{
    AdvancedOrderParams, CancelOrderParams, LimitOrderParams, Network, OrderExecutionType,
    OstiumClient, PositionSide, Result, StopOrderParams, UpdateLimitOrderParams,
};
use rust_decimal_macros::dec;
use std::env;

#[tokio::main]
async fn main() -> Result<()> {
    // Initialize logging
    tracing_subscriber::fmt::init();

    println!("🚀 Ostium Rust SDK - Advanced Order Types Example");
    println!("=================================================");

    // Get private key from environment variable
    let private_key = env::var("OSTIUM_PRIVATE_KEY").unwrap_or_else(|_| {
        println!("❌ CRITICAL: No OSTIUM_PRIVATE_KEY environment variable found!");
        println!("   This example requires a REAL private key for mainnet trading.");
        println!("   Set it with: export OSTIUM_PRIVATE_KEY=your_private_key_here");
        println!("   ⚠️  WARNING: This will use REAL MONEY on mainnet!");
        println!("   Exiting to prevent accidental transactions with dummy key...");
        std::process::exit(1);
    });

    // Create a client with a private key for trading
    println!("\n📡 Connecting to Ostium mainnet with signer...");
    let client = OstiumClient::builder(Network::Mainnet)
        .with_private_key(&private_key)?
        .build()
        .await?;

    println!("✅ Connected to network: {:?}", client.config().network);

    if let Some(address) = client.signer_address() {
        println!("👤 Signer address: {}", address);
    } else {
        println!("❌ No signer configured");
        return Ok(());
    }

    // Check if trading pairs are available
    println!("\n🔍 Checking mainnet trading pairs availability...");
    let pairs = client.get_pairs().await?;
    let active_pairs: Vec<_> = pairs.iter().filter(|p| p.is_active).collect();

    if active_pairs.is_empty() {
        println!("⚠️  No active trading pairs found on mainnet.");
        println!("   This is unexpected for mainnet - please check network connectivity.");
        println!("   The following examples will demonstrate the API structure but may fail:");
        println!("   • Limit orders");
        println!("   • Stop orders");
        println!("   • Order updates");
        println!("   • Order cancellation");
        println!("\n📚 Available pairs:");
        for (i, pair) in pairs.iter().take(10).enumerate() {
            println!(
                "  {}. {} (Status: {})",
                i + 1,
                pair.symbol,
                if pair.is_active { "Active" } else { "Inactive" }
            );
        }
    } else {
        println!("✅ Found {} active trading pairs", active_pairs.len());
        for pair in &active_pairs {
            println!("{}", pair.symbol);
        }
    }

    // Choose a symbol to test with - prefer an active pair if available
    let test_symbol = if active_pairs.is_empty() {
        "BTC/USD".to_string() // Fallback to BTC/USD for demonstration
    } else {
        active_pairs[0].symbol.clone() // Use the first active pair
    };

    // Get current price for the test symbol to base our orders on
    println!("\n📊 Getting current {} price...", test_symbol);
    let current_price = match client.get_price(&test_symbol).await {
        Ok(price) => {
            println!("✅ Current {} price: ${}", test_symbol, price.mark_price);
            price.mark_price
        }
        Err(e) => {
            println!("⚠️  Failed to get price: {}", e);
            println!("   Using default price for demonstration");
            dec!(50000) // Default price for demo
        }
    };

    // Example 1: Place a Limit Order
    println!("\n📈 Example 1: Placing a Limit Order");
    println!("===================================");

    let limit_price = current_price * dec!(0.98); // 2% below current price
    println!(
        "Setting limit order at ${} (2% below current price)",
        limit_price
    );

    let limit_params = LimitOrderParams {
        symbol: test_symbol.clone(),
        side: PositionSide::Long,
        size: dec!(0.005),   // 0.005 BTC
        leverage: dec!(3.0), // 3x leverage
        limit_price,
        take_profit: Some(current_price * dec!(1.10)), // 10% profit target
        stop_loss: Some(current_price * dec!(0.92)),   // 8% stop loss
    };

    println!("📋 Limit Order Parameters:");
    println!("  • Symbol: {}", limit_params.symbol);
    println!("  • Side: {:?}", limit_params.side);
    println!("  • Size: {}", limit_params.size);
    println!("  • Leverage: {}x", limit_params.leverage);
    println!("  • Limit Price: ${}", limit_params.limit_price);
    println!(
        "  • Take Profit: ${}",
        limit_params.take_profit.unwrap_or_default()
    );
    println!(
        "  • Stop Loss: ${}",
        limit_params.stop_loss.unwrap_or_default()
    );

    match client.place_limit_order(limit_params).await {
        Ok(tx_hash) => {
            println!("✅ Limit order placed successfully!");
            println!("  • Transaction Hash: {}", tx_hash);
        }
        Err(e) => {
            println!("⚠️  Failed to place limit order: {}", e);
            if e.to_string().contains("Failed to get pair index") {
                println!("   This indicates the trading pair may not be properly configured.");
                println!("   Please check if the symbol is correct and the pair is active.");
            }
        }
    }

    // Example 2: Place a Stop Order
    println!("\n📉 Example 2: Placing a Stop Order");
    println!("==================================");

    let stop_price = current_price * dec!(1.05); // 5% above current price
    println!(
        "Setting stop order at ${} (5% above current price)",
        stop_price
    );

    let stop_params = StopOrderParams {
        symbol: test_symbol.clone(),
        side: PositionSide::Long,
        size: dec!(0.003),   // 0.003 BTC
        leverage: dec!(2.0), // 2x leverage
        stop_price,
        take_profit: Some(current_price * dec!(1.15)), // 15% profit target
        stop_loss: Some(current_price * dec!(0.95)),   // 5% stop loss
    };

    println!("📋 Stop Order Parameters:");
    println!("  • Symbol: {}", stop_params.symbol);
    println!("  • Side: {:?}", stop_params.side);
    println!("  • Size: {}", stop_params.size);
    println!("  • Leverage: {}x", stop_params.leverage);
    println!("  • Stop Price: ${}", stop_params.stop_price);
    println!(
        "  • Take Profit: ${}",
        stop_params.take_profit.unwrap_or_default()
    );
    println!(
        "  • Stop Loss: ${}",
        stop_params.stop_loss.unwrap_or_default()
    );

    match client.place_stop_order(stop_params).await {
        Ok(tx_hash) => {
            println!("✅ Stop order placed successfully!");
            println!("  • Transaction Hash: {}", tx_hash);
        }
        Err(e) => {
            println!("⚠️  Failed to place stop order: {}", e);
            if e.to_string().contains("Failed to get pair index") {
                println!("   This indicates the trading pair may not be properly configured.");
                println!("   Please check if the symbol is correct and the pair is active.");
            }
        }
    }

    // Example 3: Advanced Order with Validation
    println!("\n🔍 Example 3: Advanced Order with Price Validation");
    println!("==================================================");

    let advanced_price = current_price * dec!(0.95); // 5% below current price

    // Validate the price first
    match client
        .validate_order_price(&test_symbol, OrderExecutionType::Limit, advanced_price)
        .await
    {
        Ok(is_valid) => {
            if is_valid {
                println!("✅ Order price ${} is valid", advanced_price);

                let advanced_params = AdvancedOrderParams {
                    symbol: test_symbol.clone(),
                    side: PositionSide::Short,
                    size: dec!(0.002),   // 0.002 BTC
                    leverage: dec!(4.0), // 4x leverage
                    order_type: OrderExecutionType::Limit,
                    price: Some(advanced_price),
                    take_profit: Some(current_price * dec!(0.85)), // 15% profit on short
                    stop_loss: Some(current_price * dec!(1.05)),   // 5% stop loss on short
                    slippage_tolerance: dec!(0.01),                // 1% slippage
                };

                match client.place_advanced_order(advanced_params).await {
                    Ok(tx_hash) => {
                        println!("✅ Advanced order placed successfully!");
                        println!("  • Transaction Hash: {}", tx_hash);
                    }
                    Err(e) => {
                        println!("⚠️  Failed to place advanced order: {}", e);
                        if e.to_string().contains("Failed to get pair index") {
                            println!("   This indicates the trading pair may not be properly configured.");
                            println!(
                                "   Please check if the symbol is correct and the pair is active."
                            );
                        }
                    }
                }
            } else {
                println!("❌ Order price ${} is not valid", advanced_price);
            }
        }
        Err(e) => {
            println!("⚠️  Failed to validate order price: {}", e);
        }
    }

    // Example 4: Update an existing limit order
    println!("\n✏️  Example 4: Updating a Limit Order");
    println!("====================================");

    // In a real scenario, you'd get the order ID from the placed orders
    let example_order_id = format!("{}:0:0", client.signer_address().unwrap());
    let new_limit_price = current_price * dec!(0.96); // New limit price

    let update_params = UpdateLimitOrderParams {
        order_id: example_order_id.clone(),
        limit_price: Some(new_limit_price),
        take_profit: Some(current_price * dec!(1.12)), // Updated take profit
        stop_loss: None,                               // Keep current stop loss
    };

    println!("📋 Update Parameters:");
    println!("  • Order ID: {}", update_params.order_id);
    println!("  • New Limit Price: ${}", new_limit_price);
    println!(
        "  • New Take Profit: ${}",
        update_params.take_profit.unwrap_or_default()
    );

    match client.update_limit_order(update_params).await {
        Ok(tx_hash) => {
            println!("✅ Limit order updated successfully!");
            println!("  • Transaction Hash: {}", tx_hash);
        }
        Err(e) => {
            println!("⚠️  Failed to update limit order: {}", e);
            if e.to_string().contains("execution reverted") {
                println!("   This is expected when the order doesn't exist or has already been executed.");
            }
        }
    }

    // Example 5: Cancel an order
    println!("\n❌ Example 5: Canceling an Order");
    println!("===============================");

    let cancel_params = CancelOrderParams {
        order_id: example_order_id.clone(),
    };

    println!("📋 Cancel Parameters:");
    println!("  • Order ID: {}", cancel_params.order_id);

    match client.cancel_order(cancel_params).await {
        Ok(tx_hash) => {
            println!("✅ Order canceled successfully!");
            println!("  • Transaction Hash: {}", tx_hash);
        }
        Err(e) => {
            println!("⚠️  Failed to cancel order: {}", e);
            if e.to_string().contains("execution reverted") {
                println!("   This is expected when the order doesn't exist or has already been executed.");
            }
        }
    }

    // Summary of order types and their use cases
    println!("\n📚 Summary: Order Types and Use Cases");
    println!("====================================");
    println!("🎯 LIMIT ORDERS:");
    println!("   • Buy below current price or sell above current price");
    println!("   • Only execute at your specified price or better");
    println!("   • Good for: Getting better entry prices, avoiding slippage");

    println!("\n🛑 STOP ORDERS:");
    println!("   • Trigger when price crosses your stop level");
    println!("   • Execute as market order once triggered");
    println!("   • Good for: Momentum trading, breakout strategies");

    println!("\n⚙️  ORDER MANAGEMENT:");
    println!("   • Update: Modify price, take profit, or stop loss");
    println!("   • Cancel: Remove pending orders before execution");
    println!("   • Validate: Check if order price is reasonable");

    println!("\n🔧 Best Practices:");
    println!("   • Always validate order prices before placing");
    println!("   • Set appropriate take profit and stop loss levels");
    println!("   • Monitor your orders and market conditions");
    println!("   • Use proper position sizing based on your risk tolerance");

    println!("\n✨ Advanced order types example completed!");
    println!("\n📚 Important Notes:");
    println!("   • This example uses MAINNET - REAL MONEY IS INVOLVED!");
    println!("   • Orders placed will be actual trades with real funds");
    println!("   • Always verify your private key and account balance before running");
    println!("   • Start with small amounts to test functionality");
    println!("   • Keep your private keys secure and never commit them to code");
    println!("   • Consider market conditions when setting order prices");
    println!("   • Symbol format: Use 'BTC/USD' format - the SDK handles conversion internally");
    println!("   • Monitor your positions and orders actively");
    println!("   • Use appropriate risk management strategies");

    Ok(())
}