Utility crates#
Besides the exchange adapters, the workspace has small crates for the work around trading. Each one is a facade feature; turn on only what you use.
tradersdk = { git = "https://github.com/suenot/tradersdk", default-features = false, features = ["bybit", "trading", "utils", "notifications"] }
None of them needs an exchange connection except warming and api.
trading: position math#
Pure functions, no I/O.
use tradersdk_trading::{calculate_position_size, calculate_pnl};
let qty = calculate_position_size(100.0, 10, 50_000.0); // 0.02
let pnl = calculate_pnl(50_000.0, 51_000.0, qty, "long", 10);
println!("{:.2} USDT, ROI {:.1}%", pnl.pnl_usdt, pnl.roi_percent);
Also: calculate_split_orders (equal parts, last one takes the rounding), calculate_limit_orders_grid, calculate_aggregate_pnl, calculate_fifo_pnl, and an Exchange enum with symbol formatting (format_symbol_for_exchange). Percentages are 0 to 100, ROI is multiplied by leverage, and fees are not included.
utils: retry and time#
use tradersdk_utils::{retry_with_backoff, RetryConfig};
let price = retry_with_backoff(&RetryConfig::new(3), || async {
trader.get_current_price("BTCUSDT").await
}).await?;
Defaults: 3 retries after the first try, 100 ms base delay, doubling, 10 s cap, 10% jitter (applied after the cap). Time helpers convert Unix milliseconds to DateTime<Utc> and format durations.
storage: caches, files, PnL log#
MemoryCache<K, V> with optional TTL, FileStorage (JSON files, one per key), a small PriceCache, and PnLTracker for closed-trade statistics. In-process state only. Expired cache entries stay in len until cleanup_expired, and the size cap evicts an arbitrary entry, not the least recently used. FileStorage keys are not sanitized, so never pass user input as a key.
price-cache: USD prices on disk#
PriceCache::new(path, freshness_hours) loads and saves a JSON file; CoinGeckoClient fills it with a rate limiter. Use uppercase symbols as keys.
leverage-cache: leverage ceilings from a file#
LeverageCacheManager reads a JSON file of per-exchange, per-symbol maximum leverage and values you have set. Lookups fall back to the default you pass to new. A missing file makes load return Ok(false).
monitoring: new and delisted markets#
use tradersdk_monitoring::{MarketDiffDetector, MarketInfo};
let mut d = MarketDiffDetector::new();
d.load_initial(vec![MarketInfo::new("BTCUSDT", "BTC/USDT")]);
let changes = d.detect_changes(vec![MarketInfo::new("ETHUSDT", "ETH/USDT")]);
// one Removed (BTCUSDT) and one Added (ETHUSDT)
The first detect_changes call without a baseline only sets the baseline. An empty snapshot counts as "not initialized".
notifications: Telegram and webhooks#
use tradersdk_notifications::NotificationManager;
let mut n = NotificationManager::new();
n.add_telegram("alerts", &std::env::var("TG_TOKEN")?, 123456789);
n.add_webhook("hook", "https://example.com/hook");
n.notify_trade("BTCUSDT", "Buy", 50_000.0, 0.1).await;
Delivery is best effort. send_all goes through the channels one after another. Webhooks retry 3 times with a growing delay and can sign the JSON body with HMAC when you set a secret.
signal: duplicate filter#
SignalProcessor accepts the first copy of a message and rejects repeats. It compares the message text, not message_id. Defaults: 10,000 entries, 30-day TTL.
proxy: rotation and scheduling#
ProxyManager hands out proxies round-robin with a cooldown, and RequestScheduler runs a fetch function on an interval with a worker limit. It does not cancel an in-flight request on stop.
warming: server-time pings#
ServerTimeWarmer calls the public server-time endpoint of Bybit, Binance, BingX, MEXC, XT, OKX, Gate and Bitget, records latency, and has a circuit breaker. AccountDetector groups bot configs that share one API key.
api: HTTP test server#
ApiServer::new(host, port, config_path).start() serves GET /api/v1/health, /exchanges, /exchanges/methods, /exchanges/bots and POST /api/v1/exchanges/test. The config holds API keys. CORS allows any origin, so bind to localhost and do not expose it.
schema-export#
A binary that writes JSON Schema for the core models: cargo run -p tradersdk-schema-export -- schemas. Useful for non-Rust consumers.