Configuration Guide

Complete reference for configuration settings


Overview

The bot uses a unified configuration system with support for TOML configuration files and environment variables. All variables have sensible defaults and are validated on startup.

Configuration Loading Flow

flowchart TD
    subgraph Priority["Configuration Loading Priority"]
        direction TB
        ENV["πŸ”΄ Environment Variables<br/>WEALTH__SECTION__FIELD<br/>(Highest Priority)"]
        TOML["🟑 TOML/JSON Config File<br/>config.toml or config.json"]
        DEF["🟒 Default Values<br/>(Fallback)"]
    end
    
    ENV --> TOML --> DEF
    
    style ENV fill:#ffcdd2
    style TOML fill:#fff9c4
    style DEF fill:#c8e6c9

Configuration Structure

flowchart LR
    subgraph Config["AppConfig Structure"]
        direction TB
        APP[AppConfig]
        APP --> INST[instruments]
        APP --> DISC[instrument_discovery]
        APP --> LEV[leverage]
        APP --> TRADE[trading]
        APP --> RISK[risk]
        APP --> EXEC[execution]
        APP --> OBS[observability]
        APP --> LIC[licensing]
    end
    
    style APP fill:#e3f2fd
    style TRADE fill:#fff3e0
    style RISK fill:#ffcdd2

Current Version: The bot uses a simplified configuration structure with direct field access.

Configuration Files:

  • config.toml - Main configuration file (instruments, leverage, trading params) - Preferred
  • config.json - Legacy JSON format (still supported for backward compatibility)
  • .env - Local environment configuration for sensitive values

Hot-Reload Support: The bot supports runtime configuration updates for safe parameters without requiring a restart. See Configuration Hot-Reload for details on which parameters can be hot-reloaded.

Configuration Architecture:

  • AppConfig - Single unified configuration structure
  • Direct field access: config.trading.*, config.risk.*, config.leverage.*
  • Environment variables with WEALTH__ prefix override TOML/JSON settings

Loading Priority:

  1. Environment variables with WEALTH__ prefix (highest priority)
  2. TOML/JSON configuration file (config.toml or config.json)
  3. Default values (fallback)

Configuration Sections

The configuration is organized into clear sections:

SectionDescription
instrumentsTrading pairs to monitor
instrument_discoveryDynamic pair discovery settings
leveragePer-symbol leverage settings
tradingStrategy parameters (spread thresholds, position sizing)
riskRisk management (slippage, trailing stops, fees)
pair_healthPair health monitoring and auto-disable thresholds
executionExecution mode (paper/live), resilience, and reconciliation
observabilityMetrics, logging, telemetry
licensingLicense configuration

Environment Variable Overrides:

  • All configuration can be overridden via environment variables
  • Prefix pattern: WEALTH__SECTION__FIELD (e.g., WEALTH__TRADING__MIN_FUNDING_SPREAD)

Trading Configuration

WEALTH__TRADING__MIN_FUNDING_SPREAD

Minimum funding rate spread required to open a position.

  • Type: Decimal (0.0-1.0)
  • Default: 0.04 (0.04% = 4 bps)
  • TOML Path: trading.min_funding_spread
  • Example: WEALTH__TRADING__MIN_FUNDING_SPREAD=0.05

WEALTH__TRADING__MAX_POSITION_USD

Maximum position size cap in USD (safety limit).

  • Type: Decimal
  • Default: 10000 ($10,000)
  • TOML Path: trading.max_position_usd
  • Example: WEALTH__TRADING__MAX_POSITION_USD=20000

WEALTH__TRADING__POSITION_SIZE_PERCENT

Percentage of available balance to use per position.

  • Type: Decimal (0.0 - 1.0)
  • Default: 0.3 (30%)
  • TOML Path: trading.position_size_percent
  • Example: WEALTH__TRADING__POSITION_SIZE_PERCENT=0.25

WEALTH__TRADING__TARGET_PROFIT_PERCENT

Target profit percentage per position.

  • Type: Decimal (0.0 - 1.0)
  • Default: 0.05 (5%)
  • TOML Path: trading.target_profit_percent
  • Example: WEALTH__TRADING__TARGET_PROFIT_PERCENT=0.08

WEALTH__TRADING__MAX_POSITION_DURATION_HOURS

Maximum position duration in hours before forced exit. Prevents capital from being tied up indefinitely.

  • Type: Integer
  • Default: 168 (7 days)
  • TOML Path: trading.max_position_duration_hours
  • Example: WEALTH__TRADING__MAX_POSITION_DURATION_HOURS=336
  • Note: Set to 0 to disable duration-based exits

WEALTH__TRADING__NARROW_SPREAD_EXIT_PERIODS

Number of consecutive narrow spread periods (8-hour intervals) before closing position.

  • Type: Integer
  • Default: 3 (24 hours of narrow spread)
  • TOML Path: trading.narrow_spread_exit_periods
  • Example: WEALTH__TRADING__NARROW_SPREAD_EXIT_PERIODS=2
  • Note: Set to 0 for immediate spread narrowing exit

WEALTH__TRADING__MAX_CONCURRENT_POSITIONS

Maximum number of concurrent arbitrage pairs.

  • Type: Integer
  • Default: 5
  • TOML Path: trading.max_concurrent_positions
  • Example: WEALTH__TRADING__MAX_CONCURRENT_POSITIONS=3

WEALTH__TRADING__UPDATE_INTERVAL_SECS

Funding rate update interval in seconds.

  • Type: Integer
  • Default: 60
  • TOML Path: trading.update_interval_secs
  • Example: WEALTH__TRADING__UPDATE_INTERVAL_SECS=30

WEALTH__TRADING__MAX_HEDGE_ATTEMPTS

Maximum number of hedging attempts for partial fills.

  • Type: Integer
  • Default: 5
  • TOML Path: trading.max_hedge_attempts
  • Example: WEALTH__TRADING__MAX_HEDGE_ATTEMPTS=3
  • Purpose: Prevents infinite hedging loops when orders partially fill

WEALTH__TRADING__HEDGE_TOLERANCE_PERCENT

Hedging tolerance as percentage (when to stop hedging).

  • Type: Decimal (0.0-1.0)
  • Default: 0.001 (0.1%)
  • TOML Path: trading.hedge_tolerance_percent
  • Example: WEALTH__TRADING__HEDGE_TOLERANCE_PERCENT=0.0005
  • Purpose: Allows small quantity mismatches without additional hedging orders

WEALTH__TRADING__FALLBACK_PRICE_USD

Fallback price in USD used when real-time price data is unavailable.

  • Type: Decimal
  • Default: 100000 ($100,000)
  • TOML Path: trading.fallback_price_usd
  • Example: WEALTH__TRADING__FALLBACK_PRICE_USD=95000
  • Purpose: Last-resort value for position sizing calculations when WebSocket price feeds fail
  • Note: Set to approximately current BTC price for reasonable position sizing. An error is logged when fallback is used.

WEALTH__TRADING__SYMBOL_FALLBACK_PRICES

Per-symbol fallback prices when real-time data is unavailable.

  • Type: Map<String, Decimal>
  • Default: Empty (uses global fallback_price_usd)
  • TOML Path: trading.symbol_fallback_prices
  • Purpose: Provides accurate fallback prices for non-BTC symbols, improving position sizing accuracy

Example TOML Configuration:

[trading.symbol_fallback_prices]
BTCUSDT = 100000
ETHUSDT = 3500
SOLUSDT = 200
XRPUSDT = 2.5

Note: Symbol-specific fallback prices take precedence over the global fallback_price_usd. Only configure symbols you actively trade.

Note: Leverage is configured per-symbol in the [leverage] section, not as a global trading parameter.

Expected Value (EV) Gating

The bot uses expected value analysis to filter opportunities before execution. Only opportunities with positive risk-adjusted EV after costs are considered.

WEALTH__TRADING__MIN_EXPECTED_VALUE

Minimum expected value threshold (net profit after costs).

  • Type: Decimal (0.0-1.0)
  • Default: 0.05 (0.05% = 5 bps)
  • TOML Path: trading.min_expected_value
  • Example: WEALTH__TRADING__MIN_EXPECTED_VALUE=0.08
  • Purpose: Filters out low-quality opportunities with insufficient edge
  • Formula: EV = (time_weighted_spread Γ— 3 funding payments) - (entry_fees + exit_fees + slippage)
  • Note: Time weighting applies linear decay based on minutes until next funding payment

WEALTH__TRADING__STALENESS_PENALTY

Discount applied to EV calculation when data age exceeds staleness haircut threshold.

  • Type: Decimal (0.0-1.0)
  • Default: 0.03 (0.03% = 3 bps)
  • TOML Path: trading.staleness_penalty
  • Example: WEALTH__TRADING__STALENESS_PENALTY=0.05
  • Purpose: Conservative adjustment for potential data lag
  • When Applied: Reduces gross EV when funding rate data age exceeds staleness_haircut_threshold_secs (default: 120s)

WEALTH__TRADING__STALENESS_HAIRCUT_THRESHOLD_SECS

Data age threshold (in seconds) for applying staleness penalty.

  • Type: Integer (seconds)
  • Default: 120 (2 minutes)
  • TOML Path: trading.staleness_haircut_threshold_secs
  • Example: WEALTH__TRADING__STALENESS_HAIRCUT_THRESHOLD_SECS=180
  • Purpose: Defines when funding rate data is considered "semi-stale" and warrants a penalty
  • Note: Distinct from data rejection threshold - data older than 5 minutes is rejected entirely

Example EV Calculation:

Funding spread: 90 bps (0.0090)
Time to funding: 240 minutes (50% of 8h period)
Time weight: 0.5
Gross EV: 90 bps Γ— 0.5 = 45 bps

Entry fees (both sides): 4 bps
Exit fees (both sides): 4 bps
Estimated slippage: 10 bps
Total costs: 18 bps

Adjusted EV: 45 - 18 = 27 bps
Passes threshold: 27 bps > 5 bps βœ…

Kelly Position Sizing

The bot supports two position sizing modes: Kelly Criterion (dynamic, risk-adjusted) or Fixed Percentage (simple, predictable).

WEALTH__TRADING__USE_KELLY_CRITERION

Enable or disable Kelly Criterion for position sizing.

  • Type: Boolean
  • Default: true
  • TOML Path: trading.use_kelly_criterion
  • Example: WEALTH__TRADING__USE_KELLY_CRITERION=false
  • When true: Uses Kelly Criterion formula for dynamic sizing based on EV and variance
  • When false: Uses fixed percentage sizing: size = min(balance) Γ— max_exchange_utilization Γ— leverage
  • Recommendation: true for optimal capital allocation, false for simpler, predictable sizing

WEALTH__TRADING__KELLY_FRACTION

Fraction of full Kelly size to use (0.0 - 1.0).

  • Type: Decimal
  • Default: 0.25 (quarter-Kelly for conservative sizing)
  • TOML Path: trading.kelly_fraction
  • Example: WEALTH__TRADING__KELLY_FRACTION=0.5
  • Purpose: Reduces risk by using only a fraction of the mathematically optimal Kelly size
  • Recommendation: Keep at 0.25 or lower for funding rate arbitrage

WEALTH__TRADING__MAX_NOTIONAL_PER_SYMBOL

Maximum notional value per symbol across all exchanges in USD.

  • Type: Decimal
  • Default: 10000 ($10,000)
  • TOML Path: trading.max_notional_per_symbol
  • Example: WEALTH__TRADING__MAX_NOTIONAL_PER_SYMBOL=20000
  • Purpose: Hard cap on position size regardless of Kelly calculation
  • Applied: Per symbol across all exchanges (e.g., total BTC exposure)

WEALTH__TRADING__MAX_EXCHANGE_UTILIZATION

Maximum percentage of free balance to use for a single position (0.0 - 1.0).

  • Type: Decimal
  • Default: 0.5 (50%)
  • TOML Path: trading.max_exchange_utilization
  • Example: WEALTH__TRADING__MAX_EXCHANGE_UTILIZATION=0.3
  • Purpose: Prevents over-concentration on one exchange
  • Reference Capital: Uses min(long_exchange_balance, short_exchange_balance) for sizing

Example Kelly Sizing:

EV: 30 bps per 8h (0.003)
Variance: 0.0001 (estimated spread volatility)
Kelly fraction: EV / variance = 0.003 / 0.0001 = 30
Reference capital: min($50,000, $80,000) = $50,000
Leverage: 10x
Full Kelly size: $50,000 Γ— 30 Γ— 10 = $15,000,000 (unrealistic)

Apply kelly_cap (0.25): $15,000,000 Γ— 0.25 = $3,750,000
Apply max_notional cap: min($3,750,000, $10,000) = $10,000
Apply utilization cap: min($10,000, $50,000 Γ— 0.5) = $10,000

Final position size: $10,000 (binding constraint: notional cap)

Leverage Configuration

Leverage multiplies your position size relative to margin. Higher leverage means higher potential returns AND higher risk of liquidation.

WEALTH__LEVERAGE__DEFAULT

Default leverage for all symbols.

  • Type: Integer OR "max"
  • Default: 3
  • TOML Path: leverage.default
  • Example: WEALTH__LEVERAGE__DEFAULT=10 or WEALTH__LEVERAGE__DEFAULT=max

Supported Values:

  • Numbers: Fixed leverage (e.g., 3, 5, 10, 20)
  • "max": Automatically use the maximum leverage allowed by each exchange

Per-Symbol Overrides

You can configure different leverage for specific symbols using the [leverage.overrides] section:

[leverage]
default = 10  # Default 10x for most symbols

[leverage.overrides]
BTCUSDT = 5       # Lower leverage for BTC (less volatile)
ETHUSDT = 8       # Medium leverage for ETH
SOLUSDT = "max"   # Use max allowed for SOL

Symmetric Leverage for Hedged Positions

When trading hedged positions across exchanges, the bot automatically ensures consistent leverage:

  1. If config is a fixed number: Uses that value (clamped to exchange max if needed)
  2. If config is "max": Uses min(max_exchange_A, max_exchange_B)

Example:

  • Config: SOLUSDT = "max"
  • Binance max for SOL: 75x
  • HyperLiquid max for SOL: 50x
  • Result: Bot uses 50x on both exchanges

This ensures the hedge ratio remains balanced regardless of differing exchange limits.

Max Leverage Caching

When using "max" leverage:

  • Max leverage is fetched from exchange APIs on startup
  • Results are cached to avoid API rate limits
  • Cache is refreshed when bot restarts

Exchange API Sources:

  • Binance: /fapi/v1/leverageBracket (uses first tier max)
  • Bybit: /v5/market/instruments-info (leverageFilter.maxLeverage)
  • HyperLiquid: /info meta endpoint (universe[].maxLeverage)
  • Aster: Binance-compatible API
Risk ProfileDefaultHigh-Volume (BTC/ETH)Mid-Cap (SOL/XRP)
Conservative332
Moderate105-810
Aggressive"max"20"max"

Note: Higher leverage increases both potential gains and liquidation risk. The bot does NOT automatically manage position size based on leverageβ€”that's controlled by position_size_percent and max_position_usd.

Slippage Protection Configuration

WEALTH__RISK__MAX_SLIPPAGE_BPS

Maximum allowed slippage in basis points.

  • Type: Integer
  • Default: 50 (0.5%)
  • TOML Path: risk.max_slippage_bps
  • Example: WEALTH__RISK__MAX_SLIPPAGE_BPS=30

WEALTH__RISK__MIN_SLIPPAGE_BPS

Minimum slippage buffer in basis points (always applied).

  • Type: Integer
  • Default: 10 (0.1%)
  • TOML Path: risk.min_slippage_bps
  • Example: WEALTH__RISK__MIN_SLIPPAGE_BPS=5

WEALTH__RISK__MARKET_ORDER_FALLBACK_ENABLED

Whether to fall back to MARKET orders if LIMIT order doesn't fill.

  • Type: Boolean
  • Default: true
  • TOML Path: risk.market_order_fallback_enabled
  • Values: true | false
  • Example: WEALTH__RISK__MARKET_ORDER_FALLBACK_ENABLED=false

WEALTH__RISK__LIMIT_ORDER_TIMEOUT_SECS

Timeout before falling back to MARKET order (seconds).

  • Type: Integer
  • Default: 5
  • TOML Path: risk.limit_order_timeout_secs
  • Example: WEALTH__RISK__LIMIT_ORDER_TIMEOUT_SECS=10

WEALTH__RISK__SLIPPAGE_VOLATILITY_MULTIPLIER

Multiplier to increase slippage tolerance in volatile markets.

  • Type: Float
  • Default: 1.5 (50% wider)
  • TOML Path: risk.slippage_volatility_multiplier
  • Example: WEALTH__RISK__SLIPPAGE_VOLATILITY_MULTIPLIER=2.0

Post-Only (Maker) Order Configuration

Post-only orders ensure you always pay maker fees instead of taker fees, significantly reducing execution costs.

WEALTH__RISK__USE_POST_ONLY

Enable post-only (maker) order execution.

  • Type: Boolean
  • Default: false
  • TOML Path: risk.use_post_only
  • Values: true | false
  • Example: WEALTH__RISK__USE_POST_ONLY=true

Exchange-Specific Order Types:

ExchangePost-Only TypeAPI Parameter
Binance FuturesGTX (Good-Til-Crossing)timeInForce=GTX
Bybit PerpetualsPostOnlytimeInForce=PostOnly
HyperLiquidAlo (Add Liquidity Only)tif=Alo
Aster FuturesGTXtimeInForce=GTX

WEALTH__RISK__LIMIT_PRICE_OFFSET_BPS

Price offset from market for post-only orders (basis points).

  • Type: Integer
  • Default: 10 (0.10%)
  • TOML Path: risk.limit_price_offset_bps
  • Example: WEALTH__RISK__LIMIT_PRICE_OFFSET_BPS=15

How it works:

  • Buy orders: Place at market_price Γ— (1 - offset_bps/10000)
  • Sell orders: Place at market_price Γ— (1 + offset_bps/10000)

WEALTH__RISK__POST_ONLY_RETRY_COUNT

Number of retry attempts when post-only order is rejected.

  • Type: Integer
  • Default: 3
  • TOML Path: risk.post_only_retry_count
  • Example: WEALTH__RISK__POST_ONLY_RETRY_COUNT=5

Retry Logic:

  1. Post-only order placed at calculated price
  2. If rejected (would cross spread), price adjusted deeper into book
  3. Repeat up to post_only_retry_count times
  4. If all retries fail and market_order_fallback_enabled=true, fall back to market order

Fee Savings Example:

ExchangeMaker FeeTaker FeeSavings per $10k Trade
Binance VIP 00.02%0.05%$3.00
Bybit Regular0.02%0.055%$3.50
HyperLiquid Tier 00.015%0.045%$3.00

Trailing Stop Configuration

Note: Trailing stop configuration is defined in config.toml or via environment variables below.

WEALTH__RISK__TRAILING_STOPS_ENABLED

Enable trailing stop loss functionality.

  • Type: Boolean
  • Default: true
  • TOML Path: risk.trailing_stops_enabled
  • Values: true | false
  • Example: WEALTH__RISK__TRAILING_STOPS_ENABLED=true

WEALTH__RISK__TRAILING_STOP_ACTIVATION

Profit threshold to activate trailing stop (as decimal percentage).

  • Type: Decimal (0.0-1.0)
  • Default: 0.03 (3%)
  • TOML Path: risk.trailing_stop_activation
  • Example: WEALTH__RISK__TRAILING_STOP_ACTIVATION=0.05

WEALTH__RISK__TRAILING_STOP_DISTANCE

Maximum allowed profit retracement before exit (as decimal percentage).

  • Type: Decimal (0.0-1.0)
  • Default: 0.40 (40% from peak)
  • TOML Path: risk.trailing_stop_distance
  • Example: WEALTH__RISK__TRAILING_STOP_DISTANCE=0.3

WEALTH__RISK__TRAILING_STOP_MIN_LOCK

Minimum profit to lock in (prevents exit below this level).

  • Type: Decimal (0.0-1.0)
  • Default: 0.02 (2%)
  • TOML Path: risk.trailing_stop_min_lock
  • Example: WEALTH__RISK__TRAILING_STOP_MIN_LOCK=0.015

WEALTH__RISK__SLIPPAGE_AWARE_EXITS

Consider estimated slippage cost in exit decisions. When enabled, positions with remaining potential profit less than expected closing costs may be held for one more funding period.

  • Type: Boolean
  • Default: true
  • TOML Path: risk.slippage_aware_exits
  • Example: WEALTH__RISK__SLIPPAGE_AWARE_EXITS=false

Fee Configuration

WEALTH__RISK__FEES__ESTIMATED_SLIPPAGE

Estimated slippage for market orders (as decimal).

  • Type: Decimal (0.0-1.0)
  • Default: 0.001 (0.1%)
  • TOML Path: risk.fees.estimated_slippage
  • Example: WEALTH__RISK__FEES__ESTIMATED_SLIPPAGE=0.002

Exchange Fee Overrides

Override default exchange fee rates in config.toml under [risk.fees.<exchange>]:

Binance

[risk.fees.binance]
maker = 0.0002  # 0.02% - Maker fee
taker = 0.0004  # 0.04% - Taker fee
funding_interval_hours = 8

Bybit

[risk.fees.bybit]
maker = 0.0001  # 0.01% - Maker fee
taker = 0.0006  # 0.06% - Taker fee
funding_interval_hours = 8

HyperLiquid

[risk.fees.hyperliquid]
maker = 0.0000   # 0.00% - Maker rebate
taker = 0.00035  # 0.035% - Taker fee
funding_interval_hours = 1  # HyperLiquid uses hourly funding (24x daily)

Note: HyperLiquid processes funding every hour, unlike most CEXes which use 8-hour intervals. This affects EV calculations and provides more frequent profit collection opportunities.

Aster

[risk.fees.aster]
maker = 0.0002   # 0.02% - Maker fee
taker = 0.0005   # 0.05% - Taker fee
funding_interval_hours = 4  # Aster uses 4h or 8h per-symbol (fetched dynamically)

Note: Aster funding intervals vary by symbol (4h or 8h). The bot automatically fetches per-symbol intervals via the API and caches them. The config value is a fallback only.

Instrument Discovery Configuration

Dynamic pair discovery settings for automatic symbol detection (v0.30+). These settings control how the bot discovers and manages trading pairs from external sources like Loris.tools.

WEALTH__INSTRUMENT_DISCOVERY__USE_LORIS_RANKINGS

Enable Loris.tools-based pair discovery for top funding rate opportunities.

  • Type: Boolean
  • Default: false
  • TOML Path: instrument_discovery.use_loris_rankings
  • Example: WEALTH__INSTRUMENT_DISCOVERY__USE_LORIS_RANKINGS=true
  • Prerequisite: Requires enabled = true or --discover CLI flag

WEALTH__INSTRUMENT_DISCOVERY__REFRESH_INTERVAL_HOURS

Periodic refresh interval for Loris.tools pair discovery (hours, 0 = disabled).

  • Type: Integer (hours)
  • Default: 0 (disabled - discovery runs only at startup)
  • TOML Path: instrument_discovery.refresh_interval_hours
  • Example: WEALTH__INSTRUMENT_DISCOVERY__REFRESH_INTERVAL_HOURS=6
  • Prerequisite: Requires use_loris_rankings = true and discovery enabled

Behavior:

  • When > 0: Periodically queries Loris.tools API to discover new high-opportunity pairs
  • Add-only strategy: New pairs are added automatically; pairs with active positions are never removed
  • Jitter protection: Random 0-30 minute delay added to prevent synchronized API requests across multiple bot instances
  • WebSocket integration: Automatically registers new pairs with price and funding rate streams

When to Enable:

ScenarioRecommended Value
Long-running production bot that should adapt to market changes6 (6 hours)
Short-term trading sessions or manual pair management0 (disabled)
Stable, predictable instrument sets preferred0 (disabled)

Note: The instrument list may grow over time with add-only logic. Use hot-reload config changes to manually prune symbols if needed.

WEALTH__INSTRUMENT_DISCOVERY__MAX_SYMBOLS

Maximum number of symbols to discover from Loris.tools rankings.

  • Type: Integer
  • Default: 20
  • TOML Path: instrument_discovery.max_symbols
  • Example: WEALTH__INSTRUMENT_DISCOVERY__MAX_SYMBOLS=30

WEALTH__INSTRUMENT_DISCOVERY__ENABLED

Enable dynamic pair discovery (requires both config and CLI flag for safety).

  • Type: Boolean
  • Default: false
  • TOML Path: instrument_discovery.enabled
  • Example: WEALTH__INSTRUMENT_DISCOVERY__ENABLED=true

When enabled, the bot discovers trading pairs automatically instead of using static [[instruments]] configuration. Requires double opt-in: set enabled = true in config AND use --enable-discovery CLI flag.

WEALTH__INSTRUMENT_DISCOVERY__EXCHANGES

Exchanges to use for pair discovery. If empty, all exchanges with credentials are used.

  • Type: Array of strings
  • Default: [] (all available exchanges)
  • TOML Path: instrument_discovery.exchanges
  • Example: WEALTH__INSTRUMENT_DISCOVERY__EXCHANGES=binance_futures,hyper_liquid

Options: binance_futures, bybit_perpetuals_usd, hyper_liquid

WEALTH__INSTRUMENT_DISCOVERY__MIN_24H_VOLUME_USD

Minimum 24-hour trading volume in USD for discovered pairs.

  • Type: Integer (USD)
  • Default: 1000000 ($1M)
  • TOML Path: instrument_discovery.min_24h_volume_usd
  • Example: WEALTH__INSTRUMENT_DISCOVERY__MIN_24H_VOLUME_USD=5000000

Higher values select more liquid pairs with lower slippage. Recommended range: $1M-$10M depending on position sizes.

WEALTH__INSTRUMENT_DISCOVERY__QUOTE_ASSET

Quote asset filter for discovered pairs.

  • Type: String
  • Default: USDT
  • TOML Path: instrument_discovery.quote_asset
  • Example: WEALTH__INSTRUMENT_DISCOVERY__QUOTE_ASSET=USDC

Options: USDT, USDC, BUSD

WEALTH__INSTRUMENT_DISCOVERY__EXCLUDE

Symbols to exclude from discovery (substring matching, case-sensitive).

  • Type: Array of strings
  • Default: ["BULL", "BEAR", "UP", "DOWN", "HEDGE", "DEFI"]
  • TOML Path: instrument_discovery.exclude
  • Example: WEALTH__INSTRUMENT_DISCOVERY__EXCLUDE=BULL,BEAR,SHIB

Use to manually block leveraged tokens, sector baskets, or specific pairs. Example: "BULL" matches "BULLISH", "BULLUSDT", "ETHBULL".

WEALTH__INSTRUMENT_DISCOVERY__MIN_EXCHANGES

Minimum number of exchanges that must support a symbol for it to be discovered.

  • Type: Integer
  • Default: 2
  • TOML Path: instrument_discovery.min_exchanges
  • Example: WEALTH__INSTRUMENT_DISCOVERY__MIN_EXCHANGES=3

Ensures arbitrage is possible (need at least 2 exchanges). Set higher to only trade pairs available on 3+ exchanges.

WEALTH__INSTRUMENT_DISCOVERY__LORIS_SORT_BY

Sorting strategy when using Loris.tools API for discovery.

  • Type: String
  • Default: arbitrage
  • TOML Path: instrument_discovery.loris_sort_by
  • Example: WEALTH__INSTRUMENT_DISCOVERY__LORIS_SORT_BY=oi_rank

Options:

  • arbitrage - Sort by funding rate spread (highest arbitrage opportunity first)
  • oi_rank - Sort by Binance open interest ranking (most liquid first)

Only applies when use_loris_rankings = true.

WEALTH__INSTRUMENT_DISCOVERY__FORCE_REMOVE_PAIRS

Force removal of pairs during hot-reload even if they have pending orders.

  • Type: Boolean
  • Default: false
  • TOML Path: instrument_discovery.force_remove_pairs
  • Example: WEALTH__INSTRUMENT_DISCOVERY__FORCE_REMOVE_PAIRS=true

Behavior:

  • When true: Auto-cancels all pending orders for removed symbols
  • When false: Blocks removal if symbol has pending orders or active positions

⚠️ Use with caution - may result in unhedged positions if orders are cancelled mid-execution.

Example Configuration

[instrument_discovery]
enabled = true
use_loris_rankings = true
loris_sort_by = "arbitrage"
refresh_interval_hours = 6
max_symbols = 20
min_24h_volume_usd = 1000000
quote_asset = "USDT"
min_exchanges = 2
exclude = ["BULL", "BEAR", "UP", "DOWN", "HEDGE", "DEFI"]
force_remove_pairs = false
# exchanges = ["binance_futures", "hyper_liquid"]  # Optional: limit to specific exchanges

Metrics Server Configuration

WEALTH__OBSERVABILITY__METRICS_PORT

Port for metrics and health check server.

  • Type: Integer
  • Default: 9090
  • TOML Path: observability.metrics_port
  • Example: WEALTH__OBSERVABILITY__METRICS_PORT=8080

WEALTH__OBSERVABILITY__METRICS_BIND_ADDRESS

Bind address for metrics server.

  • Type: String (IP address)
  • Default: 0.0.0.0 (all interfaces)
  • TOML Path: observability.metrics_bind_address
  • Example: WEALTH__OBSERVABILITY__METRICS_BIND_ADDRESS=127.0.0.1

Execution Mode

WEALTH__EXECUTION__MODE

Execution mode for order placement.

  • Type: String ("paper" | "live" | "dryrun")
  • Default: paper
  • TOML Path: execution.mode
  • Example: WEALTH__EXECUTION__MODE=live

Modes:

  • paper - Simulated trading with mock order fills
  • live - Real trading with actual exchange orders
  • dryrun - Logs order intent but doesn't execute (useful for testing strategy logic)

Note: The old PAPER_TRADING and DRY_RUN boolean flags have been replaced with WEALTH__EXECUTION__MODE in v0.33.0 for clearer semantics.

Exchange Credentials

Credential Loading Strategy

The bot automatically tries to load credentials in the following order:

  1. Encrypted Credentials File (if CREDENTIALS_PASSPHRASE is set)

    • Uses credentials.encrypted.json and .credentials.salt
    • Most secure, recommended for production
    • Managed via wealth credentials CLI commands
  2. Environment Variables (fallback)

    • Exchange-specific variables documented below
    • Simpler for development and testing

No configuration needed - the bot seamlessly uses whichever method you set up.

Initial Setup:

# 1. Set passphrase in .env
echo "CREDENTIALS_PASSPHRASE=your-secure-passphrase" >> .env

# 2. Create encrypted credentials file
wealth credentials create

# 3. Add exchange credentials (interactive mode - recommended)
wealth credentials add binance
# Or with flags (less secure - visible in shell history)
wealth credentials add binance --api-key YOUR_API_KEY --secret-key YOUR_SECRET_KEY
wealth credentials add bybit --api-key YOUR_API_KEY --secret-key YOUR_SECRET_KEY
wealth credentials add hyperliquid --api-key 0xWALLET_ADDRESS --secret-key 0xPRIVATE_KEY

# 4. Verify
wealth verify --encrypted

Advantages:

  • AES-256-GCM encryption
  • Credentials never stored in plaintext
  • Secure key derivation from passphrase (PBKDF2 with 100,000 iterations)
  • Isolated from source code and version control

Security:

  • Never commit credentials.encrypted.json or .credentials.salt to version control
  • Use a strong passphrase (12+ characters, mix of types)
  • Store passphrase securely (password manager, secrets vault)

CREDENTIALS_PASSPHRASE

Passphrase for encrypting/decrypting the credentials file.

  • Type: String
  • Default: None (not set)
  • Example: CREDENTIALS_PASSPHRASE=my-super-secure-passphrase-2024
  • Required for: Encrypted credentials (Option 1)
  • Not needed for: Direct environment variables (Option 2)

When set: Bot loads credentials from credentials.encrypted.json
When not set: Bot will fail to start (encrypted credentials are required since v0.21.0)

Note: Direct exchange credential environment variables (e.g., BINANCE_API_KEY) were deprecated in v0.21.0 and have been removed. Use encrypted credentials for all deployments. See Security Guide for setup instructions.

Resilience Configuration

WEALTH__EXECUTION__RESILIENCE__CIRCUIT_BREAKER_FAILURES

Number of failures before circuit breaker opens.

  • Type: Integer
  • Default: 5
  • TOML Path: execution.resilience.circuit_breaker_failures
  • Example: WEALTH__EXECUTION__RESILIENCE__CIRCUIT_BREAKER_FAILURES=10

WEALTH__EXECUTION__RESILIENCE__CIRCUIT_BREAKER_TIMEOUT_SECS

Time to wait before testing recovery.

  • Type: Integer
  • Default: 60
  • TOML Path: execution.resilience.circuit_breaker_timeout_secs
  • Example: WEALTH__EXECUTION__RESILIENCE__CIRCUIT_BREAKER_TIMEOUT_SECS=120

WEALTH__EXECUTION__RESILIENCE__CIRCUIT_BREAKER_SUCCESS_THRESHOLD

Number of successful calls needed to close circuit breaker.

  • Type: Integer
  • Default: 2
  • TOML Path: execution.resilience.circuit_breaker_success_threshold
  • Example: WEALTH__EXECUTION__RESILIENCE__CIRCUIT_BREAKER_SUCCESS_THRESHOLD=3

WEALTH__EXECUTION__RESILIENCE__MAX_RETRIES

Maximum retry attempts for API calls.

  • Type: Integer
  • Default: 3
  • TOML Path: execution.resilience.max_retries
  • Example: WEALTH__EXECUTION__RESILIENCE__MAX_RETRIES=5

WEALTH__EXECUTION__RESILIENCE__RETRY_INITIAL_BACKOFF_MS

Initial retry backoff in milliseconds.

  • Type: Integer
  • Default: 100
  • TOML Path: execution.resilience.retry_initial_backoff_ms
  • Example: WEALTH__EXECUTION__RESILIENCE__RETRY_INITIAL_BACKOFF_MS=200

WEALTH__EXECUTION__RESILIENCE__RETRY_MAX_BACKOFF_SECS

Maximum retry backoff in seconds.

  • Type: Integer
  • Default: 10
  • TOML Path: execution.resilience.retry_max_backoff_secs
  • Example: WEALTH__EXECUTION__RESILIENCE__RETRY_MAX_BACKOFF_SECS=30

WEALTH__EXECUTION__RESILIENCE__WEBSOCKET_MAX_RECONNECTS

Maximum WebSocket reconnection attempts.

  • Type: Integer
  • Default: 100
  • TOML Path: execution.resilience.websocket_max_reconnects
  • Example: WEALTH__EXECUTION__RESILIENCE__WEBSOCKET_MAX_RECONNECTS=50

Position Reconciliation Configuration

Position reconciliation is a background task that monitors for unhedged positions and can automatically fix them. This is recommended for live trading to catch issues like partial fills that weren't properly hedged.

The reconciliation task monitors two types of positions:

  1. Tracked positions - Positions opened by the bot and tracked by the AtomicOrderExecutor
  2. Orphan positions - Positions found on exchanges but NOT tracked by the bot (requires explicit opt-in)

WEALTH__EXECUTION__RECONCILIATION__ENABLED

Enable background position reconciliation task.

  • Type: Boolean
  • Default: false
  • TOML Path: execution.reconciliation.enabled
  • Example: WEALTH__EXECUTION__RECONCILIATION__ENABLED=true

Note: Reconciliation only runs in live trading mode. Paper trading doesn't have real positions to reconcile.

WEALTH__EXECUTION__RECONCILIATION__CHECK_INTERVAL_SECS

Interval between reconciliation checks in seconds.

  • Type: Integer
  • Default: 30
  • TOML Path: execution.reconciliation.check_interval_secs
  • Example: WEALTH__EXECUTION__RECONCILIATION__CHECK_INTERVAL_SECS=60

Lower values detect issues faster but use more CPU. Typical range: 15-60 seconds.

WEALTH__EXECUTION__RECONCILIATION__AUTO_FIX_ENABLED

Enable automatic fixing of unhedged positions tracked by the bot.

  • Type: Boolean
  • Default: true
  • TOML Path: execution.reconciliation.auto_fix_enabled
  • Example: WEALTH__EXECUTION__RECONCILIATION__AUTO_FIX_ENABLED=false

When enabled, unhedged positions that are tracked by the AtomicOrderExecutor are automatically closed via emergency close. When disabled, only alerts are triggered and manual intervention is required.

WEALTH__EXECUTION__RECONCILIATION__AUTO_CLOSE_ORPHANS

Enable automatic closing of orphan positions not tracked by the bot.

  • Type: Boolean
  • Default: false
  • TOML Path: execution.reconciliation.auto_close_orphans
  • Example: WEALTH__EXECUTION__RECONCILIATION__AUTO_CLOSE_ORPHANS=true

⚠️ CAUTION: When enabled, the reconciliation task will automatically close ANY unhedged position found on exchanges that is NOT being tracked by the bot. This includes positions:

  • Created manually outside the bot
  • Left over from a previous bot session that crashed
  • Opened by other trading systems on the same account

Only enable this if you exclusively use this bot for trading on the configured exchanges. When disabled (default), orphan positions trigger critical alerts but require manual intervention.

WEALTH__EXECUTION__RECONCILIATION__STUCK_EXECUTION_THRESHOLD_SECS

Threshold for stuck execution alerts in seconds.

  • Type: Integer
  • Default: 60
  • TOML Path: execution.reconciliation.stuck_execution_threshold_secs
  • Example: WEALTH__EXECUTION__RECONCILIATION__STUCK_EXECUTION_THRESHOLD_SECS=60

Alert when an execution has been running longer than this threshold. Reduced from 300s to 60s for faster detection of stuck executions that could lead to liquidation. Typical range: 30-120 seconds.

WEALTH__EXECUTION__RECONCILIATION__EMERGENCY_CLOSE_FAILURE_THRESHOLD

Maximum consecutive emergency close failures before auto-shutdown.

  • Type: Integer
  • Default: 3
  • TOML Path: execution.reconciliation.emergency_close_failure_threshold
  • Example: WEALTH__EXECUTION__RECONCILIATION__EMERGENCY_CLOSE_FAILURE_THRESHOLD=3

When this threshold is reached, the bot will automatically initiate a graceful shutdown to prevent further losses from unhedged positions. This is a critical safety feature to prevent liquidation during cascading failures. Set to 0 to disable auto-shutdown (not recommended).

WEALTH__EXECUTION__RECONCILIATION__HYPERLIQUID_CLOSE_SLIPPAGE

Slippage percentage for HyperLiquid force close operations.

  • Type: Float (0.0 - 1.0)
  • Default: 0.05 (5%)
  • TOML Path: execution.reconciliation.hyperliquid_close_slippage
  • Example: WEALTH__EXECUTION__RECONCILIATION__HYPERLIQUID_CLOSE_SLIPPAGE=0.05

This slippage setting is used in two scenarios:

  1. Orphan Position Closing: When closing orphan positions on HyperLiquid during reconciliation
  2. Atomic Executor Fallback: When reduce_only close orders return zero fill but positions still exist (v0.52+)

Higher values increase the chance of fill but may result in worse execution prices. The default 5% is recommended for reliable closes.

Note: This uses HyperLiquid's SDK market_close function which fetches the current position state directly from the exchange before closing, making it more reliable than standard reduce_only orders.

Pair Health Configuration

The pair health system monitors trading pair health to detect degraded or broken data feeds. Unhealthy pairs can be automatically disabled to prevent bad trades.

WEALTH__PAIR_HEALTH__ENABLED

Enable automatic health monitoring for trading pairs.

  • Type: Boolean
  • Default: true
  • TOML Path: pair_health.enabled
  • Example: WEALTH__PAIR_HEALTH__ENABLED=false

When enabled, the system tracks WebSocket disconnections, API errors, and data staleness for each trading pair.

WEALTH__PAIR_HEALTH__MAX_WS_DISCONNECTIONS

Maximum consecutive WebSocket disconnections before marking pair unhealthy.

  • Type: Integer
  • Default: 5
  • TOML Path: pair_health.max_ws_disconnections
  • Example: WEALTH__PAIR_HEALTH__MAX_WS_DISCONNECTIONS=10

WEALTH__PAIR_HEALTH__MAX_API_ERRORS

Maximum consecutive API errors before marking pair unhealthy.

  • Type: Integer
  • Default: 10
  • TOML Path: pair_health.max_api_errors
  • Example: WEALTH__PAIR_HEALTH__MAX_API_ERRORS=15

WEALTH__PAIR_HEALTH__MAX_FUNDING_RATE_STALENESS_SECS

Maximum age of funding rate data in seconds before considered stale.

  • Type: Integer
  • Default: 300 (5 minutes)
  • TOML Path: pair_health.max_funding_rate_staleness_secs
  • Example: WEALTH__PAIR_HEALTH__MAX_FUNDING_RATE_STALENESS_SECS=600

Funding rate data older than this threshold is excluded from opportunity detection. This prevents trading on outdated market data.

WEALTH__PAIR_HEALTH__MAX_PRICE_STALENESS_SECS

Maximum age of price data in seconds before considered stale.

  • Type: Integer
  • Default: 60 (1 minute)
  • TOML Path: pair_health.max_price_staleness_secs
  • Example: WEALTH__PAIR_HEALTH__MAX_PRICE_STALENESS_SECS=120

WEALTH__PAIR_HEALTH__AUTO_DISABLE_UNHEALTHY

Automatically disable pairs that become unhealthy.

  • Type: Boolean
  • Default: false
  • TOML Path: pair_health.auto_disable_unhealthy
  • Example: WEALTH__PAIR_HEALTH__AUTO_DISABLE_UNHEALTHY=true

When true, pairs are auto-disabled when health thresholds are exceeded. When false (default), pairs stay enabled but show unhealthy status in TUI.

WEALTH__PAIR_HEALTH__AUTO_REENABLE_HEALTHY

Automatically re-enable pairs after they become healthy again.

  • Type: Boolean
  • Default: true
  • TOML Path: pair_health.auto_reenable_healthy
  • Example: WEALTH__PAIR_HEALTH__AUTO_REENABLE_HEALTHY=false

WEALTH__PAIR_HEALTH__HEALTHY_CHECKS_FOR_REENABLE

Number of consecutive healthy checks before re-enabling auto-disabled pair.

  • Type: Integer
  • Default: 3
  • TOML Path: pair_health.healthy_checks_for_reenable
  • Example: WEALTH__PAIR_HEALTH__HEALTHY_CHECKS_FOR_REENABLE=5

WEALTH__PAIR_HEALTH__CHECK_INTERVAL_SECS

Health check interval in seconds.

  • Type: Integer
  • Default: 30
  • TOML Path: pair_health.check_interval_secs
  • Example: WEALTH__PAIR_HEALTH__CHECK_INTERVAL_SECS=60

Example Configuration:

[pair_health]
enabled = true
max_ws_disconnections = 5
max_api_errors = 10
max_funding_rate_staleness_secs = 300
max_price_staleness_secs = 60
auto_disable_unhealthy = false
auto_reenable_healthy = true
healthy_checks_for_reenable = 3
check_interval_secs = 30

Observability Configuration

WEALTH__OBSERVABILITY__METRICS_PORT

Port number for the metrics/API server.

  • Type: u16
  • Default: 9090
  • TOML Path: observability.metrics_port
  • Example: WEALTH__OBSERVABILITY__METRICS_PORT=9090

The metrics server exposes:

  • /metrics - OpenTelemetry metrics info (JSON)
  • /health, /ready, /live - Health check endpoints
  • /api/positions, /api/funding_rates, /api/balances - HTTP API for querying bot state
  • /api/arbitrage_positions - Cached arbitrage positions with funding collected (fast, no API quota)

WEALTH__OBSERVABILITY__METRICS_BIND_ADDRESS

IP address for the metrics/API server to bind to.

  • Type: IP Address
  • Default: 0.0.0.0 (all network interfaces)
  • TOML Path: observability.metrics_bind_address
  • Example: WEALTH__OBSERVABILITY__METRICS_BIND_ADDRESS=127.0.0.1

Set to 127.0.0.1 for localhost-only access (recommended for production with external proxy).

WEALTH__OBSERVABILITY__OTLP_ENDPOINT

OpenTelemetry Protocol (OTLP) endpoint URL for exporting traces, metrics, and logs.

  • Type: String (URL)
  • Default: None (OTLP export disabled, local logging only)
  • TOML Path: observability.otlp_endpoint
  • Example: WEALTH__OBSERVABILITY__OTLP_ENDPOINT=http://localhost:4317

When set, the bot will export all telemetry (traces, metrics, logs) to an OpenTelemetry Collector or compatible backend (Tempo, Jaeger, etc.) via gRPC. This replaces the previous Loki push logging with a unified observability pipeline.

URL Validation:

  • Must start with http:// or https://
  • Default port for OTLP gRPC is 4317
  • Supports authentication via standard OTLP headers (configure in collector)

Resource Attributes: You can add custom resource attributes via the OTEL_RESOURCE_ATTRIBUTES environment variable:

export OTEL_RESOURCE_ATTRIBUTES="service.name=wealth-bot,deployment.environment=production,service.version=0.16.0"

WEALTH__OBSERVABILITY__SERVICE_NAME

Service name for telemetry resource attributes.

  • Type: String
  • Default: wealth
  • TOML Path: observability.service_name
  • Example: WEALTH__OBSERVABILITY__SERVICE_NAME=wealth-prod

Used as the service.name resource attribute in OpenTelemetry spans, metrics, and logs. Useful when running multiple bot instances.

WEALTH__OBSERVABILITY__ENVIRONMENT

Environment name for telemetry resource attributes (e.g., production, development, staging).

  • Type: String
  • Default: development
  • TOML Path: observability.environment
  • Example: WEALTH__OBSERVABILITY__ENVIRONMENT=production

Used as a custom resource attribute for environment-based filtering in observability backends.

WEALTH__OBSERVABILITY__ENABLE_TRACES

Enable distributed tracing via OTLP.

  • Type: Boolean
  • Default: true
  • TOML Path: observability.enable_traces
  • Example: WEALTH__OBSERVABILITY__ENABLE_TRACES=false

When enabled alongside otlp_endpoint, exports trace spans to the OTLP endpoint for distributed tracing visualization in Tempo, Jaeger, or similar backends.

WEALTH__OBSERVABILITY__TRACE_SAMPLE_RATE

Trace sampling rate (0.0 = never sample, 1.0 = always sample).

  • Type: Decimal (0.0 - 1.0)
  • Default: 1.0 (100% of traces)
  • TOML Path: observability.trace_sample_rate
  • Example: WEALTH__OBSERVABILITY__TRACE_SAMPLE_RATE=0.1

Lower values reduce observability costs in high-throughput scenarios. Recommended: 1.0 for development, 0.1-0.01 for high-volume production.

WEALTH__OBSERVABILITY__LOG_FILE

Path to log file for file-based logging.

  • Type: String (file path)
  • Default: None (logs to stdout only)
  • TOML Path: observability.log_file
  • Example: WEALTH__OBSERVABILITY__LOG_FILE=/var/log/wealth.log

When set, logs are written to both stdout and the specified file. Useful for debugging without disrupting OTLP telemetry.

Configuration Methods:

  1. Environment Variables:

    export WEALTH__OBSERVABILITY__OTLP_ENDPOINT=http://localhost:4317
    export WEALTH__OBSERVABILITY__SERVICE_NAME=wealth-prod
    export WEALTH__OBSERVABILITY__ENVIRONMENT=production
    
  2. TOML Config:

    [observability]
    otlp_endpoint = "http://localhost:4317"
    service_name = "wealth-prod"
    environment = "production"
    
  3. JSON Config (Legacy):

    {
      "observability": {
        "otlp_endpoint": "http://localhost:4317",
        "service_name": "wealth-prod",
        "environment": "production"
      }
    }
    

Configuration Precedence: Environment variables > TOML config > JSON config (legacy) > Defaults

See Logging Guide for complete OpenTelemetry setup instructions.

Configuration Examples

Development (Paper Trading)

# Trading
WEALTH__TRADING__MIN_FUNDING_SPREAD=0.04
WEALTH__TRADING__MAX_POSITION_USD=10000
WEALTH__TRADING__POSITION_SIZE_PERCENT=0.3
WEALTH__TRADING__TARGET_PROFIT_PERCENT=0.05

# Execution
WEALTH__EXECUTION__MODE=paper

# Observability
RUST_LOG=info
# Optional: Enable OTLP export for development
WEALTH__OBSERVABILITY__OTLP_ENDPOINT=http://localhost:4317
WEALTH__OBSERVABILITY__SERVICE_NAME=wealth-dev
WEALTH__OBSERVABILITY__ENVIRONMENT=development

Production (Live Trading)

# Trading
WEALTH__TRADING__MIN_FUNDING_SPREAD=0.04
WEALTH__TRADING__MAX_POSITION_USD=50000
WEALTH__TRADING__POSITION_SIZE_PERCENT=0.25
WEALTH__TRADING__TARGET_PROFIT_PERCENT=0.05

# Execution
WEALTH__EXECUTION__MODE=live

# Exchange Credentials (use encrypted credentials file instead)
CREDENTIALS_PASSPHRASE="your-secure-passphrase"

# Observability
RUST_LOG=info
WEALTH__OBSERVABILITY__OTLP_ENDPOINT=https://otlp.example.com:4317
WEALTH__OBSERVABILITY__SERVICE_NAME=wealth-prod
WEALTH__OBSERVABILITY__ENVIRONMENT=production

Testing Configuration

# Execution
WEALTH__EXECUTION__MODE=paper

# Conservative settings
WEALTH__TRADING__MAX_POSITION_USD=100
WEALTH__TRADING__POSITION_SIZE_PERCENT=0.1

# Verbose logging
RUST_LOG=debug

Configuration Validation

All configuration is validated on startup with fail-fast behavior.

Validation Process:

  • Type validation during JSON parsing (serde)
  • Cross-field validation after loading
  • Clear error messages indicating which rule failed

Validated Constraints:

  • All numeric thresholds must be positive
  • Percentages must be between 0 and 1
  • Port numbers must be non-zero
  • At least one instrument must be configured
  • Retry counts and timeouts must be valid

Example Error:

ERROR Configuration validation failed: Metrics port must be non-zero
ERROR Configuration validation failed: At least one instrument must be configured

Debugging Configuration

Use the config show --show-sources command to see where each configuration value comes from:

$ wealth config show --show-sources

πŸ“‹ Configuration Sources

Shows: default β†’ file (config.toml) β†’ env vars β†’ βœ“ final value

🎯 Trading Configuration:
  min_funding_spread:
    default:  0.0004
    file:     0.0005
    env:      0.0006
    βœ“ final:  0.0006 ← using environment override

  max_position_usd:
    default:  10000
    βœ“ final:  10000 ← using default

This helps identify configuration issues and understand which values are active.

Environment Variable Precedence

Configuration loading happens in this order:

  1. Environment variables with WEALTH__ prefix (highest priority) - Override all other settings
  2. TOML/JSON configuration file (config.toml or config.json) - Provides structured config
  3. Default values (lowest priority) - Built-in sensible defaults

Example: If you set WEALTH__TRADING__MIN_FUNDING_SPREAD=0.001 in .env and min_funding_spread = 0.04 in config.toml, the environment variable takes precedence.

Best Practices:

  • Use config.toml for static configuration (instruments, leverage, strategy parameters)
  • Use environment variables with WEALTH__ prefix for deployment-specific settings
  • Use encrypted credentials file for API keys (safer than environment variables)
  • Use .env file for local development overrides

Using with Different Tools

Systemd

[Service]
Environment="WEALTH__EXECUTION__MODE=live"
Environment="CREDENTIALS_PASSPHRASE=your-passphrase"

Docker

docker run -e WEALTH__EXECUTION__MODE=live \
  -e CREDENTIALS_PASSPHRASE=xxx \
  -v $(pwd)/config.toml:/app/config.toml \
  wealth

Docker Compose

environment:
  - WEALTH__EXECUTION__MODE=live
  - CREDENTIALS_PASSPHRASE=${CREDENTIALS_PASSPHRASE}
volumes:
  - ./config.toml:/app/config.toml:ro
  - ./credentials.encrypted.json:/app/credentials.encrypted.json:ro

Kubernetes

env:
- name: WEALTH__EXECUTION__MODE
  value: "live"
- name: CREDENTIALS_PASSPHRASE
  valueFrom:
    secretKeyRef:
      name: wealth-secrets
      key: credentials-passphrase
volumeMounts:
- name: config
  mountPath: /app/config.toml
  subPath: config.toml

Configuration Debugging

Config Show Sources Command

Display where each configuration value comes from (default β†’ file β†’ env):

wealth config --show-sources

Example Output:

πŸ“‹ Configuration Sources

Shows: default β†’ file (config.toml) β†’ env vars β†’ βœ“ final value

🎯 Trading Configuration:
  min_funding_spread:
    default:  0.0004
    env:      0.0008
    βœ“ final:  0.0008 ← using environment override
    
  max_position_usd:
    default:  10000
    file:     15000
    βœ“ final:  15000 ← from config file

Use cases:

  • Debug which source is being used for each config value
  • Verify environment variable overrides are working
  • Identify misconfigured values before running the bot

Validation Error Messages

Configuration errors now include source tracking (v0.33.0+):

File-based error:

Error: Invalid value for leverage.default: Must be greater than 0 
(from config file: config.toml)

Environment variable error:

Error: Invalid value for trading.min_funding_spread: Cannot be negative
(from environment variable: WEALTH__TRADING__MIN_FUNDING_SPREAD)

Default value error:

Error: Invalid value for risk.max_slippage_bps: must be positive
(using default value)

Benefits:

  • Quickly identify where the problematic value is configured
  • Avoid checking multiple configuration sources manually
  • Clear distinction between file errors and env var errors

Config Validation

Validate configuration without starting the bot:

wealth config --validate

Output:

πŸ” Validating configuration...

  βœ“ Loading config.toml
  βœ“ TOML parsing successful
  βœ“ Environment variable parsing successful
  βœ“ Validating configuration... OK

βœ… Configuration is valid!
   Instruments: 6
   Metrics Port: 9090
   Execution Mode: Paper

Common validation errors:

  • Negative values (spreads, slippage, leverage)
  • Out-of-range percentages (must be 0.0-1.0)
  • Invalid exchange names (must be: binance, bybit, hyperliquid, aster)
  • Missing required instruments

See Also