ostium-rust-sdk 0.1.0

Rust SDK for interacting with the Ostium trading platform on Arbitrum
Documentation
//! Minimum Size Constraint Validation Example
//!
//! This example demonstrates how the minimum size constraint is enforced in the Ostium Rust SDK.
//! According to Ostium documentation, the minimum collateral amount is as low as 7 USDC on some assets.
//!
//! Reference: https://ostium-labs.gitbook.io/ostium-docs/ostium-trading-engine/opening-trades

use ostium_rust_sdk::{Network, OpenPositionParams, OstiumClient, PositionSide};
use rust_decimal::Decimal;
use rust_decimal_macros::dec;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    tracing_subscriber::fmt::init();

    println!("📏 Minimum Size Constraint Validation Example");
    println!("==============================================");
    println!("Testing minimum collateral requirements based on Ostium documentation\n");

    // Initialize client
    let client = OstiumClient::new(Network::Mainnet).await?;

    // Test cases for different assets
    let test_cases = vec![
        ("BTC/USD", dec!(0.00001), 10), // Very small BTC position
        ("ETH/USD", dec!(0.001), 10),   // Small ETH position
        ("EUR/USD", dec!(0.01), 20),    // Small EUR position
        ("SPX/USD", dec!(0.1), 50),     // Small SPX position
        ("GOLD/USD", dec!(0.001), 10),  // Small Gold position
    ];

    for (symbol, size, leverage) in test_cases {
        println!("🔍 Testing minimum size validation for {}", symbol);
        println!(
            "   Position size: {} {}",
            size,
            symbol.split('/').next().unwrap()
        );
        println!("   Leverage: {}x", leverage);

        // Test the validation
        match test_minimum_size_validation(&client, symbol, size, Decimal::from(leverage)).await {
            Ok(_) => {
                println!("   ✅ Position size meets minimum requirements");
            }
            Err(e) => {
                println!("   ❌ Position size validation failed:");
                // Print each line of the error with proper indentation
                for line in e.to_string().lines() {
                    println!("      {}", line);
                }
            }
        }
        println!();
    }

    // Test with valid positions that should pass
    println!("🎯 Testing Valid Positions (Should Pass)");
    println!("==========================================");

    let valid_test_cases = vec![
        ("BTC/USD", dec!(0.1), 5),  // Reasonable BTC position
        ("ETH/USD", dec!(1.0), 5),  // Reasonable ETH position
        ("EUR/USD", dec!(1000), 2), // Standard EUR position
    ];

    for (symbol, size, leverage) in valid_test_cases {
        println!(
            "🔍 Testing {} with size {} at {}x leverage",
            symbol, size, leverage
        );

        match test_minimum_size_validation(&client, symbol, size, Decimal::from(leverage)).await {
            Ok(_) => {
                println!("   ✅ Position passed validation");
            }
            Err(e) => {
                println!("   ❌ Unexpected validation failure: {}", e);
            }
        }
        println!();
    }

    // Show minimum size information for different assets
    println!("📊 Minimum Size Information by Asset");
    println!("====================================");

    let info_symbols = vec!["BTC/USD", "ETH/USD", "EUR/USD", "SPX/USD", "GOLD/USD"];

    for symbol in info_symbols {
        match client.get_minimum_position_size(symbol).await {
            Ok(min_size) => {
                println!(
                    "   {}: minimum {} {}",
                    symbol,
                    min_size,
                    symbol.split('/').next().unwrap()
                );

                // Try to get current price to show collateral requirement
                if let Ok(price) = client.get_price(symbol).await {
                    let min_collateral_1x = min_size * price.mark_price;
                    println!("     Current price: ${:.2}", price.mark_price);
                    println!("     Min collateral (1x): ${:.2} USDC", min_collateral_1x);
                    println!(
                        "     Min collateral (10x): ${:.2} USDC",
                        min_collateral_1x / Decimal::from(10)
                    );
                }
            }
            Err(e) => {
                println!("   {}: Error getting minimum size: {}", symbol, e);
            }
        }
        println!();
    }

    println!("📖 Documentation Reference:");
    println!("   https://ostium-labs.gitbook.io/ostium-docs/ostium-trading-engine/opening-trades");
    println!("   \"Collateral: the minimum amount is as low as 7 USDC on some assets.\"");

    Ok(())
}

/// Test minimum size validation for a given position
async fn test_minimum_size_validation(
    client: &OstiumClient,
    symbol: &str,
    size: Decimal,
    leverage: Decimal,
) -> Result<(), Box<dyn std::error::Error>> {
    // Create test position parameters
    let params = OpenPositionParams {
        symbol: symbol.to_string(),
        side: PositionSide::Long,
        size,
        leverage,
        take_profit: None,
        stop_loss: None,
        slippage_tolerance: dec!(0.02), // 2%
    };

    // This will trigger the validation without actually executing the trade
    // since we don't have a signer configured
    match client
        .validate_trading_constraints(&params.symbol, params.side, params.size, params.leverage)
        .await
    {
        Ok(_) => Ok(()),
        Err(e) => Err(Box::new(e)),
    }
}