use std::str::FromStr;
use phoenix_rise::{
CandlesQueryParams, CollateralHistoryQueryParams, FundingHistoryQueryParams,
OrderHistoryQueryParams, PhoenixHttpClient, PnlQueryParams, PnlResolution, Timeframe,
TradeHistoryQueryParams,
};
use solana_pubkey::Pubkey;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
println!("Connecting to Phoenix HTTP API...\n");
let client = PhoenixHttpClient::new_from_env()?;
println!("=== Exchange Keys ===");
let exchange_keys = client.exchange().get_keys().await?;
println!(" Global Config: {}", exchange_keys.global_config);
println!(" Canonical Mint: {}", exchange_keys.canonical_mint);
println!(" Global Vault: {}", exchange_keys.global_vault);
println!(" Perp Asset Map: {}", exchange_keys.perp_asset_map);
println!(" Withdraw Queue: {}", exchange_keys.withdraw_queue);
println!(
" Trader Index Accs: {}",
exchange_keys.global_trader_index.len()
);
println!(
" Active Trader Buf: {}",
exchange_keys.active_trader_buffer.len()
);
println!("\n Current Authorities:");
println!(
" Root: {}",
exchange_keys.current_authorities.root_authority
);
println!(
" Risk: {}",
exchange_keys.current_authorities.risk_authority
);
println!(
" Market: {}",
exchange_keys.current_authorities.market_authority
);
println!(
" Oracle: {}",
exchange_keys.current_authorities.oracle_authority
);
println!();
println!("=== SOL Market Config ===");
let market = client.markets().get_market("SOL").await?;
println!(" Symbol: {}", market.symbol);
println!(" Asset ID: {}", market.asset_id);
println!(" Status: {:?}", market.market_status);
println!(" Market Pubkey: {}", market.market_pubkey);
println!(" Spline Pubkey: {}", market.spline_pubkey);
println!(" Tick Size: {}", market.tick_size);
println!(" Base Lot Decimals: {}", market.base_lots_decimals);
println!(" Isolated Only: {}", market.isolated_only);
println!("\n Fees:");
println!(" Taker Fee: {:.4}%", market.taker_fee * 100.0);
println!(" Maker Fee: {:.4}%", market.maker_fee * 100.0);
println!("\n Funding:");
println!(
" Interval: {} seconds",
market.funding_interval_seconds
);
println!(
" Period: {} seconds",
market.funding_period_seconds
);
println!(
" Max Rate/Int: {:.4}%",
market.max_funding_rate_per_interval * 100.0
);
println!("\n Leverage Tiers:");
for (i, tier) in market.leverage_tiers.iter().enumerate() {
println!(
" Tier {}: max {:.1}x leverage, max {} base lots",
i + 1,
tier.max_leverage,
tier.max_size_base_lots
);
}
println!("\n Risk Factors:");
println!(
" Maintenance: {:.2}%",
market.risk_factors.maintenance
);
println!(" Backstop: {:.2}%", market.risk_factors.backstop);
println!(" High Risk: {:.2}%", market.risk_factors.high_risk);
println!("\n Caps:");
println!(
" OI Cap: {} base lots",
market.open_interest_cap_base_lots
);
println!(
" Max Liq Size: {} base lots",
market.max_liquidation_size_base_lots
);
println!();
println!("=== SOL Candles (1m) ===");
let params = CandlesQueryParams::new("SOL", Timeframe::Minute1).with_limit(5);
let candles = client.candles().get_candles(params).await?;
println!(" Latest {} candles:", candles.len());
for candle in &candles {
println!(
" {} | O: ${:.2} H: ${:.2} L: ${:.2} C: ${:.2} V: {:.1}",
candle.time,
candle.open,
candle.high,
candle.low,
candle.close,
candle.volume.unwrap_or(0.0)
);
}
println!();
println!("=== All Markets ===");
let markets = client.markets().get_markets().await?;
println!(" Markets ({} total):", markets.len());
for m in &markets {
println!(
" {}: {:?} (max leverage: {}x, isolated: {})",
m.symbol,
m.market_status,
m.leverage_tiers
.first()
.map(|t| t.max_leverage)
.unwrap_or(0.0),
m.isolated_only
);
}
println!();
if let Ok(pubkey_str) = std::env::var("TRADER_PUBKEY") {
println!("=== Trader Subaccounts ===");
let authority = Pubkey::from_str(&pubkey_str)?;
let traders = client.traders().get_trader(&authority).await?;
println!(" Found {} subaccount(s)\n", traders.len());
for trader in &traders {
println!(
" --- Subaccount {} (PDA index: {}) ---",
trader.trader_subaccount_index, trader.trader_pda_index
);
println!(" Trader Key: {}", trader.trader_key);
println!(" State: {:?}", trader.state);
println!(" Collateral: {}", trader.collateral_balance.ui);
println!(" Portfolio Value: {}", trader.portfolio_value.ui);
println!(" Unrealized PnL: {}", trader.unrealized_pnl.ui);
println!(" Risk State: {:?}", trader.risk_state);
println!(" Risk Tier: {:?}", trader.risk_tier);
if !trader.positions.is_empty() {
println!("\n Positions:");
for pos in &trader.positions {
println!(
" {}: {} @ {} (uPnL: {})",
pos.symbol, pos.position_size.ui, pos.entry_price.ui, pos.unrealized_pnl.ui
);
}
}
let order_count: usize = trader.limit_orders.values().map(|v| v.len()).sum();
if order_count > 0 {
println!("\n Limit Orders ({} total):", order_count);
for (symbol, orders) in &trader.limit_orders {
for order in orders {
println!(
" {}: {:?} {} @ {}",
symbol, order.side, order.trade_size_remaining.ui, order.price.ui
);
}
}
}
println!();
}
println!("=== Trade History ===");
let params = TradeHistoryQueryParams::new().with_limit(10);
let trades = client
.trades()
.get_trader_trade_history(&authority, params)
.await?;
println!(" Latest {} trades:", trades.data.len());
for fill in &trades.data {
println!(
" {} | {} {} {:?} @ {} | PnL: {} | Fees: {} | {}",
fill.timestamp,
fill.market_symbol,
fill.base_lots_delta,
fill.liquidity,
fill.price,
fill.realized_pnl,
fill.fees,
fill.signature.clone().unwrap_or("N/A".to_string())
);
}
if trades.has_more {
println!(" (more trades available via pagination)");
}
println!("=== Collateral History ===");
let params = CollateralHistoryQueryParams::new(10);
let history = client
.collateral()
.get_user_collateral_history(&authority, params)
.await?;
println!(" Latest {} events:", history.data.len());
for event in &history.data {
println!(
" {} | {} {} (balance after: {})",
event.timestamp, event.event_type, event.amount, event.collateral_after
);
}
if history.has_more {
println!(" (more events available via pagination)");
}
println!();
println!("=== Funding History ===");
let params = FundingHistoryQueryParams::new().with_limit(10);
let funding = client
.funding()
.get_user_funding_history(&authority, params)
.await?;
println!(" Latest {} events:", funding.events.len());
for event in &funding.events {
println!(
" {} | {} {} USDC",
event.timestamp, event.symbol, event.funding_payment
);
}
if funding.has_more {
println!(" (more events available via pagination)");
}
println!();
println!("=== PnL (last 6 months, daily) ===");
let now_ms = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_millis() as i64;
let six_months_ago_ms = now_ms - 180 * 24 * 60 * 60 * 1000;
let params = PnlQueryParams::new(PnlResolution::Day1)
.with_start_time(six_months_ago_ms)
.with_end_time(now_ms);
let pnl = client.traders().get_trader_pnl(&authority, params).await?;
println!(" {} data points:", pnl.len());
for point in &pnl {
println!(
" {} | cumPnL: {:.2} | unrealized: {:.2} | funding: {:.2} | fees: {:.2}",
point.timestamp,
point.cumulative_pnl,
point.unrealized_pnl,
point.cumulative_funding_payment,
point.cumulative_taker_fee,
);
}
println!();
println!("=== Order History ===");
let params = OrderHistoryQueryParams::new(10);
let orders = client
.orders()
.get_trader_order_history(&authority, params)
.await?;
println!(" Latest {} orders:", orders.data.len());
for order in &orders.data {
println!(
" {} | {:?} {:?} {} @ {} ({:?})",
order.market_symbol,
order.side,
order.status,
order.base_qty,
order.price,
order
.placed_at
.map(|t| t.format("%Y-%m-%d %H:%M").to_string())
);
}
if orders.has_more {
if let Some(cursor) = &orders.next_cursor {
println!("\n Fetching next page...");
let next_params = OrderHistoryQueryParams::new(5).with_cursor(cursor);
let next_page = client
.orders()
.get_trader_order_history(&authority, next_params)
.await?;
println!(" Next {} orders:", next_page.data.len());
for order in &next_page.data {
println!(
" {} | {:?} {:?} {} @ {}",
order.market_symbol, order.side, order.status, order.base_qty, order.price
);
}
}
}
println!("\n Filtering by SOL market:");
let sol_params = OrderHistoryQueryParams::new(5).with_market_symbol("SOL");
let sol_orders = client
.orders()
.get_trader_order_history(&authority, sol_params)
.await?;
println!(" Found {} SOL orders", sol_orders.data.len());
println!();
println!("\n Filtering trades by SOL market:");
let sol_params = TradeHistoryQueryParams::new()
.with_market_symbol("SOL")
.with_limit(5);
let sol_trades = client
.trades()
.get_trader_trade_history(&authority, sol_params)
.await?;
println!(" Found {} SOL trades", sol_trades.data.len());
println!();
}
println!("=== Exchange Config ===");
let exchange = client.exchange().get_exchange().await?;
println!(" Markets ({} total):", exchange.markets.len());
for market in &exchange.markets {
println!("\n {} Market Config:", market.symbol);
println!(" Spline Collection: {}", market.spline_pubkey);
println!(
" Fees: taker {:.4}%, maker {:.4}%",
market.taker_fee * 100.0,
market.maker_fee * 100.0
);
println!(
" Funding: {} sec interval, {} sec period",
market.funding_interval_seconds, market.funding_period_seconds
);
println!(
" Max Funding Rate/Interval: {:.4}%",
market.max_funding_rate_per_interval * 100.0
);
println!(
" OI Cap: {} base lots",
market.open_interest_cap_base_lots
);
println!(
" Max Liquidation Size: {} base lots",
market.max_liquidation_size_base_lots
);
println!(" Isolated Only: {}", market.isolated_only);
println!(" Risk Factors:");
println!(" Maintenance: {:.2}%", market.risk_factors.maintenance);
println!(" Backstop: {:.2}%", market.risk_factors.backstop);
println!(" High Risk: {:.2}%", market.risk_factors.high_risk);
}
println!();
Ok(())
}