# Account API Reference
This document provides complete reference documentation for account management operations in the Ostium Rust SDK.
## Overview
The account API enables you to:
- Query account balances (USDC and other tokens)
- Retrieve open positions with PnL calculations
- Access pending orders and order history
- Monitor account performance metrics
- Check margin requirements and utilization
All account operations can be performed with or without authentication, depending on whether you're querying your own account or a public address.
## Balance Operations
### Getting Account Balance
#### `get_balance`
Retrieves comprehensive account balance information.
```rust
pub async fn get_balance(&self, address: Option<Address>) -> Result<Balance>
```
**Parameters:**
- `address: Option<Address>` - Account address to query (uses signer address if None)
**Returns:**
- `Result<Balance>` - Complete balance information
**Balance Structure:**
```rust
pub struct Balance {
pub asset: String, // Asset symbol (e.g., "USDC")
pub available: Decimal, // Available for trading
pub locked: Decimal, // Locked in orders/positions
pub total: Decimal, // Total balance (available + locked)
}
```
**Example:**
```rust
// Query your own balance (requires authenticated client)
let my_balance = client.get_balance(None).await?;
println!("My USDC Balance:");
println!(" Total: ${}", my_balance.total);
println!(" Available: ${}", my_balance.available);
println!(" Locked: ${}", my_balance.locked);
// Query another account's balance
let other_address = "0x742d35Cc6634C0532925a3b8D53A2e1c5Bc2D8db".parse()?;
let other_balance = client.get_balance(Some(other_address)).await?;
println!("Other account balance: ${}", other_balance.total);
```
**Error Handling:**
```rust
match client.get_balance(None).await {
Ok(balance) => {
println!("Balance: ${}", balance.total);
}
Err(OstiumError::Wallet(msg)) => {
eprintln!("No signer configured: {}", msg);
// Need to provide address explicitly or configure signer
}
Err(OstiumError::Network(msg)) => {
eprintln!("Network error: {}", msg);
// Retry or check connection
}
Err(e) => eprintln!("Error: {}", e),
}
```
## Position Management
### Getting Open Positions
#### `get_positions`
Retrieves all open positions for an account with current market values.
```rust
pub async fn get_positions(&self, address: Option<Address>) -> Result<Vec<Position>>
```
**Parameters:**
- `address: Option<Address>` - Account address (uses signer address if None)
**Returns:**
- `Result<Vec<Position>>` - List of open positions
**Position Structure:**
```rust
pub struct Position {
pub id: String, // Unique position identifier
pub symbol: String, // Trading pair (e.g., "BTC/USD")
pub side: PositionSide, // Long or Short
pub size: Decimal, // Position size
pub entry_price: Decimal, // Average entry price
pub mark_price: Decimal, // Current mark price
pub unrealized_pnl: Decimal, // Unrealized profit/loss
pub realized_pnl: Decimal, // Realized profit/loss
pub margin: Decimal, // Margin used
pub leverage: Decimal, // Position leverage
pub liquidation_price: Option<Decimal>, // Liquidation price
pub take_profit: Option<Decimal>, // Take profit price
pub stop_loss: Option<Decimal>, // Stop loss price
pub created_at: DateTime<Utc>, // Position creation time
pub updated_at: DateTime<Utc>, // Last update time
}
```
**Example:**
```rust
let positions = client.get_positions(None).await?;
if positions.is_empty() {
println!("No open positions");
} else {
println!("Open Positions:");
for position in positions {
println!(" {} {} {} @ ${} ({}x leverage)",
position.symbol,
match position.side {
PositionSide::Long => "Long",
PositionSide::Short => "Short",
},
position.size,
position.entry_price,
position.leverage);
// Show PnL with color coding (conceptual)
let pnl_status = if position.unrealized_pnl > Decimal::ZERO {
"🟢 PROFIT"
} else if position.unrealized_pnl < Decimal::ZERO {
"🔴 LOSS"
} else {
"⚪ BREAKEVEN"
};
println!(" Current Price: ${}", position.mark_price);
println!(" Unrealized PnL: ${} ({})", position.unrealized_pnl, pnl_status);
if let Some(liq_price) = position.liquidation_price {
println!(" Liquidation Price: ${}", liq_price);
}
if let Some(tp) = position.take_profit {
println!(" Take Profit: ${}", tp);
}
if let Some(sl) = position.stop_loss {
println!(" Stop Loss: ${}", sl);
}
println!(); // Empty line for readability
}
}
```
### Position Analysis
```rust
// Calculate total portfolio metrics
fn analyze_portfolio(positions: &[Position]) -> PortfolioMetrics {
let total_margin = positions.iter()
.map(|p| p.margin)
.sum::<Decimal>();
let total_unrealized_pnl = positions.iter()
.map(|p| p.unrealized_pnl)
.sum::<Decimal>();
let total_realized_pnl = positions.iter()
.map(|p| p.realized_pnl)
.sum::<Decimal>();
let long_positions = positions.iter()
.filter(|p| p.side == PositionSide::Long)
.count();
let short_positions = positions.iter()
.filter(|p| p.side == PositionSide::Short)
.count();
PortfolioMetrics {
total_margin,
total_unrealized_pnl,
total_realized_pnl,
position_count: positions.len(),
long_positions,
short_positions,
}
}
struct PortfolioMetrics {
total_margin: Decimal,
total_unrealized_pnl: Decimal,
total_realized_pnl: Decimal,
position_count: usize,
long_positions: usize,
short_positions: usize,
}
```
## Order Management
### Getting Open Orders
#### `get_orders`
Retrieves all pending orders for an account.
```rust
pub async fn get_orders(&self, address: Option<Address>) -> Result<Vec<Order>>
```
**Parameters:**
- `address: Option<Address>` - Account address (uses signer address if None)
**Returns:**
- `Result<Vec<Order>>` - List of pending orders
**Order Structure:**
```rust
pub struct Order {
pub id: String, // Unique order identifier
pub symbol: String, // Trading pair
pub order_type: OrderType, // Order type (Market, Limit, etc.)
pub side: PositionSide, // Long or Short
pub size: Decimal, // Order size
pub price: Option<Decimal>, // Order price (for limit orders)
pub stop_price: Option<Decimal>, // Stop price (for stop orders)
pub status: OrderStatus, // Current status
pub filled_size: Decimal, // Amount already filled
pub avg_fill_price: Option<Decimal>, // Average fill price
pub created_at: DateTime<Utc>, // Order creation time
pub updated_at: DateTime<Utc>, // Last update time
}
```
**Example:**
```rust
let orders = client.get_orders(None).await?;
if orders.is_empty() {
println!("No pending orders");
} else {
println!("Pending Orders:");
for order in orders {
println!(" {} {} {} {} @ ${}",
order.symbol,
match order.order_type {
OrderType::Market => "Market",
OrderType::Limit => "Limit",
OrderType::StopMarket => "Stop Market",
OrderType::StopLimit => "Stop Limit",
},
match order.side {
PositionSide::Long => "Long",
PositionSide::Short => "Short",
},
order.size,
order.price.unwrap_or_default());
println!(" Status: {:?}", order.status);
if order.filled_size > Decimal::ZERO {
println!(" Filled: {} / {}", order.filled_size, order.size);
}
if let Some(avg_price) = order.avg_fill_price {
println!(" Avg Fill Price: ${}", avg_price);
}
println!(); // Empty line
}
}
```
## Account Monitoring
### Real-time Account Updates
```rust
// Monitor account changes
async fn monitor_account_changes(client: &OstiumClient) -> Result<()> {
let mut last_balance = client.get_balance(None).await?;
let mut last_position_count = client.get_positions(None).await?.len();
loop {
tokio::time::sleep(Duration::from_secs(10)).await;
// Check balance changes
let current_balance = client.get_balance(None).await?;
if current_balance.total != last_balance.total {
println!("💰 Balance changed: ${} -> ${}",
last_balance.total, current_balance.total);
last_balance = current_balance;
}
// Check position changes
let current_positions = client.get_positions(None).await?;
if current_positions.len() != last_position_count {
println!("📊 Position count changed: {} -> {}",
last_position_count, current_positions.len());
last_position_count = current_positions.len();
}
// Check for positions near liquidation
for position in ¤t_positions {
if let Some(liq_price) = position.liquidation_price {
let distance_to_liq = ((position.mark_price - liq_price).abs() / position.mark_price) * Decimal::from(100);
if distance_to_liq < Decimal::from(5) { // Within 5% of liquidation
println!("⚠️ WARNING: {} position near liquidation! Distance: {}%",
position.symbol, distance_to_liq);
}
}
}
}
}
```
### Portfolio Summary
```rust
// Generate comprehensive portfolio summary
async fn get_portfolio_summary(client: &OstiumClient) -> Result<PortfolioSummary> {
let balance = client.get_balance(None).await?;
let positions = client.get_positions(None).await?;
let orders = client.get_orders(None).await?;
let total_margin_used = positions.iter()
.map(|p| p.margin)
.sum::<Decimal>();
let total_unrealized_pnl = positions.iter()
.map(|p| p.unrealized_pnl)
.sum::<Decimal>();
let margin_utilization = if balance.total > Decimal::ZERO {
(total_margin_used / balance.total) * Decimal::from(100)
} else {
Decimal::ZERO
};
Ok(PortfolioSummary {
account_value: balance.total + total_unrealized_pnl,
available_balance: balance.available,
margin_used: total_margin_used,
unrealized_pnl: total_unrealized_pnl,
margin_utilization,
open_positions: positions.len(),
pending_orders: orders.len(),
positions,
orders,
})
}
struct PortfolioSummary {
account_value: Decimal,
available_balance: Decimal,
margin_used: Decimal,
unrealized_pnl: Decimal,
margin_utilization: Decimal, // Percentage
open_positions: usize,
pending_orders: usize,
positions: Vec<Position>,
orders: Vec<Order>,
}
```
## Risk Management
### Margin Calculations
```rust
// Calculate margin requirements
fn calculate_margin_requirement(
position_size: Decimal,
price: Decimal,
leverage: Decimal,
) -> Decimal {
(position_size * price) / leverage
}
// Check if account can open new position
async fn can_open_position(
client: &OstiumClient,
params: &OpenPositionParams,
) -> Result<bool> {
let balance = client.get_balance(None).await?;
let current_price = client.get_price(¶ms.symbol).await?.mark_price;
let required_margin = calculate_margin_requirement(
params.size,
current_price,
params.leverage,
);
Ok(balance.available >= required_margin)
}
```
### Account Health Monitoring
```rust
// Monitor account health metrics
#[derive(Debug)]
struct AccountHealth {
margin_ratio: Decimal, // Available margin / Used margin
liquidation_distance: Decimal, // Average distance to liquidation
position_concentration: Decimal, // Largest position as % of account
risk_score: RiskLevel, // Overall risk assessment
}
enum RiskLevel {
Low, // < 25% margin utilization
Medium, // 25-50% margin utilization
High, // 50-75% margin utilization
Critical, // > 75% margin utilization
}
async fn assess_account_health(client: &OstiumClient) -> Result<AccountHealth> {
let balance = client.get_balance(None).await?;
let positions = client.get_positions(None).await?;
let total_margin = positions.iter().map(|p| p.margin).sum::<Decimal>();
let margin_ratio = if total_margin > Decimal::ZERO {
balance.available / total_margin
} else {
Decimal::MAX
};
// Calculate average distance to liquidation
let mut total_distance = Decimal::ZERO;
let mut count = 0;
for position in &positions {
if let Some(liq_price) = position.liquidation_price {
let distance = ((position.mark_price - liq_price).abs() / position.mark_price) * Decimal::from(100);
total_distance += distance;
count += 1;
}
}
let liquidation_distance = if count > 0 {
total_distance / Decimal::from(count)
} else {
Decimal::from(100) // No positions = no liquidation risk
};
// Find largest position as percentage of account
let largest_position = positions.iter()
.map(|p| p.margin)
.max()
.unwrap_or_default();
let position_concentration = if balance.total > Decimal::ZERO {
(largest_position / balance.total) * Decimal::from(100)
} else {
Decimal::ZERO
};
// Assess overall risk
let margin_utilization = (total_margin / balance.total) * Decimal::from(100);
let risk_score = match margin_utilization {
u if u < Decimal::from(25) => RiskLevel::Low,
u if u < Decimal::from(50) => RiskLevel::Medium,
u if u < Decimal::from(75) => RiskLevel::High,
_ => RiskLevel::Critical,
};
Ok(AccountHealth {
margin_ratio,
liquidation_distance,
position_concentration,
risk_score,
})
}
```
## Best Practices
### 1. Regular Balance Monitoring
```rust
// Check balance before every trade
async fn safe_open_position(
client: &OstiumClient,
params: OpenPositionParams,
) -> Result<()> {
// Check balance first
let balance = client.get_balance(None).await?;
let current_price = client.get_price(¶ms.symbol).await?.mark_price;
let required_margin = (params.size * current_price) / params.leverage;
if balance.available < required_margin {
return Err(OstiumError::validation(format!(
"Insufficient balance: need ${}, have ${}",
required_margin, balance.available
)));
}
// Proceed with trade
client.open_position(params).await?;
Ok(())
}
```
### 2. Position Size Management
```rust
// Calculate safe position size based on account balance
fn calculate_safe_position_size(
account_balance: Decimal,
price: Decimal,
leverage: Decimal,
max_risk_percent: Decimal, // e.g., 2% = 0.02
) -> Decimal {
let max_margin = account_balance * max_risk_percent;
(max_margin * leverage) / price
}
```
### 3. Error Handling
```rust
// Comprehensive error handling for account operations
async fn robust_account_query(client: &OstiumClient) -> Result<()> {
match client.get_positions(None).await {
Ok(positions) => {
println!("Successfully retrieved {} positions", positions.len());
}
Err(OstiumError::Wallet(msg)) => {
eprintln!("Authentication required: {}", msg);
// Prompt user to configure private key
}
Err(OstiumError::Network(msg)) => {
eprintln!("Network error: {}", msg);
// Implement retry logic
}
Err(OstiumError::GraphQL(msg)) => {
eprintln!("API error: {}", msg);
// Check API status or report issue
}
Err(e) => {
eprintln!("Unexpected error: {}", e);
}
}
Ok(())
}
```
## See Also
- [Client API Reference](client.md) - Main client interface
- [Trading API Reference](trading.md) - Trading operations
- [Types Reference](types.md) - Data structures
- [Risk Management Guide](../guides/risk-management.md) - Risk management strategies