Skip to main content
Autonome supports two trading modes: simulated (safe testing with virtual capital) and live (real trades on zkLighter exchange). The mode is controlled by the TRADING_MODE environment variable.

Trading Modes

Simulated Mode

Runs a local trading simulator that mimics exchange behavior without risking real capital. Perfect for:
  • Testing trading strategies
  • Validating AI model decisions
  • Development and debugging
  • Backtesting with live market data
Features:
  • Virtual capital (configurable starting balance)
  • Real market price data
  • Simulated order execution and fills
  • Position tracking and P&L calculation
  • No real money at risk

Live Mode

Executes real trades on the zkLighter exchange using your API credentials. Use this mode when:
  • You’ve thoroughly tested your strategy in simulation
  • You’re ready to trade with real capital
  • You understand the risks and have proper risk management
Live mode executes real trades with real money. Always test thoroughly in simulated mode first and never risk more capital than you can afford to lose.

Configuration

Set the trading mode in your .env file:
# .env or .env.local

# For safe testing (default)
TRADING_MODE=simulated

# For real trading
TRADING_MODE=live

Simulated Mode Configuration

When using TRADING_MODE=simulated, configure the simulator with these variables:
# Starting capital in quote currency
SIM_INITIAL_CAPITAL=10000

# Quote currency for positions (usually USDT)
SIM_QUOTE_CURRENCY=USDT

# How often to refresh market data (milliseconds)
SIM_REFRESH_INTERVAL_MS=10000
SIM_INITIAL_CAPITAL
number
default:"10000"
Starting capital for the simulator. This represents your virtual trading balance in the quote currency.
SIM_QUOTE_CURRENCY
string
default:"USDT"
The quote currency for all positions and P&L calculations. Typically USDT or USDC.
SIM_REFRESH_INTERVAL_MS
number
default:"10000"
Interval in milliseconds between market data refreshes. Lower values provide more real-time updates but increase API usage.

Live Mode Configuration

When using TRADING_MODE=live, you must configure Lighter API credentials:
# Lighter exchange credentials
LIGHTER_API_KEY_INDEX=2
LIGHTER_BASE_URL=https://mainnet.zklighter.elliot.ai
LIGHTER_API_KEY_INDEX
number
default:"2"
Your API key index in the zkLighter account system. Each account can have multiple key indexes.
LIGHTER_BASE_URL
string (URL)
default:"https://mainnet.zklighter.elliot.ai"
Base URL for the Lighter REST API. Use mainnet for production trading.
Your LIGHTER_API_KEY_INDEX provides access to your exchange account and funds. Never share this value or commit it to version control.

Accessing Trading Mode in Code

Use the validated constants from src/env.ts:
import { TRADING_MODE, IS_SIMULATION_ENABLED, DEFAULT_SIMULATOR_OPTIONS } from "@/env";

// Check current mode
if (IS_SIMULATION_ENABLED) {
  console.log("Running in simulated mode");
  console.log("Initial capital:", DEFAULT_SIMULATOR_OPTIONS.initialCapital);
} else {
  console.log("Running in LIVE mode - real trades!");
}

// Access mode directly
const mode = TRADING_MODE; // "simulated" | "live"

Type-Safe Mode Checking

The TRADING_MODE constant is type-checked as an enum:
import type { TradingMode } from "@/server/features/simulator/types";
import { TRADING_MODE } from "@/env";

// TypeScript knows this is "simulated" | "live"
const currentMode: TradingMode = TRADING_MODE;

// Type-safe conditional logic
if (TRADING_MODE === "live") {
  // Execute real trade
} else {
  // Execute simulated trade
}

Simulator Architecture

The exchange simulator (ExchangeSimulator) provides a high-fidelity trading environment:

Key Features

State Management:
  • Maintains virtual account balance and positions
  • Tracks open orders and execution history
  • Calculates unrealized P&L from live market prices
  • Persists state to database (rehydrates on restart)
Order Processing:
  • Validates order parameters (quantity, price, side)
  • Simulates order matching and fills
  • Applies realistic slippage and fees
  • Supports market and limit orders
Market Data:
  • Fetches real-time prices from configured data sources
  • Updates position values on price changes
  • Triggers position refreshes at configured intervals
Database Integration:
  • Stores all simulated trades in the Orders table with status="CLOSED"
  • Tracks open positions as orders with status="OPEN"
  • Maintains full audit trail of simulated trading activity

Simulator Initialization

The simulator is bootstrapped once at server startup:
// src/server/schedulers/bootstrap.ts
import { IS_SIMULATION_ENABLED } from "@/env";
import { getExchangeSimulator } from "@/server/features/simulator/instance";

export async function bootstrapSchedulers() {
  if (IS_SIMULATION_ENABLED) {
    const simulator = getExchangeSimulator();
    await simulator.initialize();
    console.log("✓ Exchange simulator initialized");
  }
}
The bootstrap is called from the API server entry point (api/src/index.ts) and guarded against duplicate initialization using schedulerState.ts.

Switching Modes

To switch between modes:
  1. Update your .env file:
    # Change this line
    TRADING_MODE=simulated  # or "live"
    
  2. Restart the application:
    # Development
    bun run dev:all
    
    # Production
    bun run build:api
    bun run start:api
    
  3. Verify the mode in logs:
    ✓ Trading mode: simulated
    ✓ Exchange simulator initialized
    
Always verify the mode after restart. There is no hot-reloading for TRADING_MODE - you must restart the server for changes to take effect.

Safety Features

Mode Isolation

Simulated and live modes are completely isolated:
  • Simulated trades never reach the real exchange
  • Live trades never interact with simulator state
  • Database records are tagged with execution context
  • Position calculations respect mode boundaries

Pre-Deployment Checklist

Before enabling live mode:
  • Thoroughly tested strategy in simulated mode
  • Verified P&L calculations are accurate
  • Confirmed risk management rules are working
  • Set appropriate position sizing limits
  • Configured stop losses and invalidation levels
  • Tested with small capital amounts first
  • Verified Lighter API credentials are correct
  • Set up monitoring and alerts
  • Documented your trading rules and expectations

Environment Validation

Validate your configuration before deployment:
bun run scripts/validate-env.ts
This script checks:
  • Required variables are set for your chosen mode
  • API keys are present (for live mode)
  • URLs are valid and reachable
  • Database connection is working
  • Simulator configuration is valid (for simulated mode)

Common Patterns

Conditional Feature Flags

Enable features based on trading mode:
import { IS_SIMULATION_ENABLED } from "@/env";

// Only show simulator controls in simulated mode
const showSimulatorControls = IS_SIMULATION_ENABLED;

// Adjust UI messaging based on mode
const orderButtonText = IS_SIMULATION_ENABLED 
  ? "Place Simulated Order" 
  : "Place Live Order";

Mode-Specific Logging

Add context to logs:
import { TRADING_MODE } from "@/env";
import * as Sentry from "@sentry/react";

Sentry.startSpan(
  { 
    name: "placeOrder",
    attributes: { tradingMode: TRADING_MODE }
  },
  async () => {
    console.log(`[${TRADING_MODE.toUpperCase()}] Placing order...`);
    // Order logic
  }
);

Testing Both Modes

Use different .env files for different scenarios:
# .env.test (for CI/automated tests)
TRADING_MODE=simulated
SIM_INITIAL_CAPITAL=10000

# .env.staging (for staging environment)
TRADING_MODE=simulated
SIM_INITIAL_CAPITAL=100000

# .env.production (for live trading)
TRADING_MODE=live
LIGHTER_API_KEY_INDEX=2

Troubleshooting

Simulator Not Initializing

Symptoms: No positions showing, orders not executing in simulated mode Solutions:
  1. Check TRADING_MODE=simulated is set
  2. Verify database connection (DATABASE_URL)
  3. Check server logs for initialization errors
  4. Ensure scheduler bootstrap completed successfully

Live Orders Not Executing

Symptoms: Orders placed but not filled in live mode Solutions:
  1. Verify TRADING_MODE=live is set
  2. Check Lighter API credentials are correct
  3. Confirm LIGHTER_BASE_URL is reachable
  4. Review exchange API logs for errors
  5. Check account balance and permissions

Mode Mismatch After Restart

Symptoms: UI shows different mode than expected Solutions:
  1. Verify .env file was saved
  2. Restart both API server and frontend
  3. Clear browser cache and reload
  4. Check for multiple .env files that might conflict

Best Practices

Development:
  • Always use simulated mode during development
  • Test edge cases with various capital amounts
  • Validate strategy performance over extended periods
  • Use realistic refresh intervals (don’t set too low)
Testing:
  • Run integration tests in simulated mode
  • Verify mode switching doesn’t break features
  • Test with both empty and populated order history
  • Validate P&L calculations match expectations
Production:
  • Never commit live API credentials
  • Use environment-specific .env files
  • Monitor mode in server logs and metrics
  • Implement circuit breakers for live trading
  • Start with minimal capital to verify behavior
Security:
  • Store live API keys in secure secret management
  • Rotate credentials regularly
  • Use separate accounts for testing and production
  • Audit all live trade executions
  • Set up alerts for unexpected trading activity

Build docs developers (and LLMs) love