Skip to content
forked from froooze/DEXBot2

Rewrite and optimize the staggered order strategy for market making in JavaScript on BitShares.

License

Notifications You must be signed in to change notification settings

bitshares/DEXBot2

ย 
ย 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

DEXBot2

A sophisticated market making bot for the BitShares Decentralized Exchange (DEX), implementing optimized staggered order strategies for automated trading.

๐Ÿš€ Features

  • Staggered Order Grid: Creates geometric order grids around market price for efficient market making.
  • Dynamic Rebalancing: Automatically adjusts orders after fills to maintain optimal spread.
  • Multi-Bot Support: Run multiple bots simultaneously on different trading pairs.
  • PM2 Process Management: Automatic restart and monitoring for production use.
  • Master Password Security: Encrypted key storage with RAM-only password handling.

โš ๏ธ Disclaimer โ€” Use At Your Own Risk

  • This software is in alpha stage and provided "asโ€‘is" without warranty.
  • Secure your keys and secrets. Do not commit private keys or passwords to anyone โ€” use profiles/ for live configuration and keep it out of source control.
  • The authors and maintainers are not responsible for losses.

๐Ÿ“ฆ Installation

# Clone the repository and switch to folder
git clone https://github.com/froooze/DEXBot2.git
cd DEXBot2

# Install dependencies (if any)
npm install

# Set up your master password and keyring
node dexbot keys

# Create and configure your bots
node dexbot bots

Updating DEXBot2

To update DEXBot2 to the latest version from the main branch:

# Run the update script from project root
bash scripts/update.sh

The update script automatically:

  • Fetches and pulls the latest code from GitHub
  • Installs any new dependencies
  • Reloads PM2 processes if running
  • Ensures your profiles/ directory is protected and unchanged
  • Logs all operations to update.log

๐Ÿ”ง Configuration

Define each bot in profiles/bots.json. A minimal structure looks like this:

{
  "bots": [
    {
      "name": "your-name",
      "active": true,
      "dryRun": true,
      "preferredAccount": "example-account",
      "assetA": "IOB.XRP",
      "assetB": "BTS",
      "marketPrice": "pool",
      "minPrice": "4x",
      "maxPrice": "4x",
      "incrementPercent": 1,
      "targetSpreadPercent": 5,
      "weightDistribution": { "sell": 0.5, "buy": 0.5 },
      "botFunds": { "sell": "100%", "buy": "100%" },
      "activeOrders": { "sell": 20, "buy": 20 }
    },
  ]
}

โš™๏ธ Configuration Options

Below is a concise description of each configuration option you may set per-bot (use these keys inside each bots entry in examples/bots.json / profiles/bots.json):

  • name: string โ€” optional friendly name for the bot. Used for logging and selection when calling CLI commands (e.g. dexbot start my-bot).
  • active: boolean โ€” if false, the bot is kept in the config but not started. Use this to keep templates in your file without running them.
  • dryRun: boolean โ€” when true the bot simulates orders and does not broadcast transactions on-chain. Use false only after you have verified your settings and secured keys.
  • preferredAccount: string โ€” the account name to use for on-chain operations; dexbot will prompt once for the master password and reuse it for all bots needing this value.
  • assetA: string โ€” human-friendly name or symbol of the base asset (the asset you are selling on a sell order). Example: "BTC", "BTS".
  • assetB: string โ€” human-friendly name or symbol of the quote asset (the asset you receive on a sell order). Example: "USD", "IOB.XRP".
  • marketPrice: number | string โ€” preferred market price. You may provide a numeric value (e.g. 42000) or let the bot derive it by setting "pool" (use liquidity pool) or "market" (use order book/ticker). If omitted the runtime will attempt to derive it from assetA/assetB.
  • minPrice: number | string โ€” lower bound for allowed order prices. You may provide a concrete numeric value (e.g. 525) or a multiplier string like "5x". When given as a multiplier the runtime resolves it relative to marketPrice (e.g. "5x" -> marketPrice / 5). Choose values that meaningfully bracket your expected market range to avoid accidental order placement far from the current price.
  • maxPrice: number | string โ€” upper bound for allowed order prices. You may provide a concrete numeric value (e.g. 8400) or a multiplier string like "5x". When given as a multiplier the runtime resolves it relative to marketPrice (e.g. "5x" -> marketPrice * 5). Choose values that meaningfully bracket your expected market range to avoid accidental order placement far from the current price.
  • incrementPercent: number โ€” percent step between adjacent order price levels (e.g. 1 means 1% steps). Smaller values produce denser grids.
  • targetSpreadPercent: number โ€” target spread (in percent) around the market price that the grid should cover. The manager uses this to place buy/sell layers around the market.
  • weightDistribution: object โ€” { "sell": <number>, "buy": <number> }. Controls order sizing shape. Values are the distribution coefficient (examples below):
    • Typical values: -1 = Super Valley (more weight far from market), 0 = Valley, 0.5 = Neutral, 1 = Mountain (more weight near market), 2 = Super Mountain.
  • botFunds: object โ€” { "sell": <number|string>, "buy": <number|string> }.
    • sell: amount of base asset allocated for selling (absolute like 0.1 or percentage string like "100%").
    • buy: amount of quote asset allocated for buying (can be an absolute number like 10000 or a percentage string like "50%").
    • buy refers to the quote-side (what you spend to buy base); sell refers to the base-side (what you sell). Provide human-readable units (not blockchain integer units).
    • If you supply percentages (e.g. "50%") the manager needs accountTotals to resolve them to absolute amounts before placing orders; otherwise provide absolute numbers.
  • activeOrders: object โ€” { "sell": <integer>, "buy": <integer> } number of sell/buy orders to keep active in the grid for each side.

โš™๏ธ CLI & Running

Single Bot (Direct)

You can run bots directly via node dexbot.js or using the dexbot CLI wrapper (installed via npm link or run with npx dexbot):

  • node dexbot.js or dexbot โ€” starts all active bots defined in profiles/bots.json (use examples/bots.json as a template).
  • dexbot start [bot_name] โ€” start a specific bot (or all active bots if omitted). Respects each bot's dryRun setting.
  • dexbot drystart [bot_name] โ€” same as start but forces dryRun=true for safe simulation.
  • dexbot stop [bot_name] โ€” mark a bot (or all bots) inactive; the config file is used the next time the process launches.
  • dexbot restart [bot_name] โ€” restart a bot and reset its order grid. This clears saved order state and regenerates the grid from scratch.
  • dexbot keys โ€” manage master password and keyring via modules/chain_keys.js.
  • dexbot bots โ€” open the interactive editor in modules/account_bots.js to create or edit bot entries.
  • dexbot --cli-examples โ€” print curated CLI snippets for common tasks.

dexbot is a thin wrapper around ./dexbot.js. You can link it for system-wide use via npm link or run it with npx dexbot.

If any active bot requires preferredAccount, dexbot will prompt once for the master password and reuse it for subsequent bots.

๐ŸŽฏ PM2 Process Management (Recommended for Production)

For production use with automatic restart and process monitoring, use PM2:

Quick Start (All Bots)

# Start all active bots with PM2
node pm2.js

# Or via CLI
node dexbot.js pm2

This unified launcher handles everything automatically:

  1. BitShares Connection: Waits for network connection
  2. PM2 Check: Detects local and global PM2; prompts to install if missing
  3. Config Generation: Creates profiles/ecosystem.config.js from profiles/bots.json
  4. Authentication: Prompts for master password (kept in RAM only, never saved to disk)
  5. Startup: Starts all active bots as PM2-managed processes with auto-restart

Single Bot via PM2

# Start a specific bot via PM2
node pm2.js <bot-name>

Same as node pm2.js but only starts the specified bot.

Individual Bot (Direct, without PM2)

# Run a single bot directly (prompts for password if not in environment)
node bot.js <bot-name>

PM2 Management Commands

After startup via node pm2.js:

# View bot status and resource usage
pm2 status

# View real-time logs from all bots (or specific bot)
pm2 logs
pm2 logs <bot-name>

# Stop all bots (or specific bot)
pm2 stop all
pm2 stop <bot-name>

# Restart all bots (or specific bot)
pm2 restart all
pm2 restart <bot-name>

# Delete all bots from PM2 (or specific bot)
pm2 delete all
pm2 delete <bot-name>

Configuration & Logs

Bot configurations are defined in profiles/bots.json. The PM2 launcher automatically:

  • Filters only bots with active !== false
  • Generates ecosystem config with proper paths and logging
  • Logs bot output to profiles/logs/<bot-name>.log
  • Logs bot errors to profiles/logs/<bot-name>-error.log
  • Applies restart policies (max 13 restarts, 1 day min uptime, 3 second restart delay)

Security

  • Master password is prompted interactively in your terminal
  • Password passed via environment variable to bot processes (RAM only)
  • Never written to disk or config files
  • Cleared when process exits

๐Ÿ” Environment Variables

Control bot behavior via environment variables (useful for advanced setups):

  • MASTER_PASSWORD - Master password for key decryption (set by pm2.js, used by bot.js and dexbot.js)
  • BOT_NAME or LIVE_BOT_NAME - Select a specific bot from profiles/bots.json by name (for single-bot runs)
  • PREFERRED_ACCOUNT - Override the preferred account for the selected bot
  • RUN_LOOP_MS - Polling interval in milliseconds (default: 5000). Controls how often the bot checks for fills and market conditions
  • CALC_CYCLES - Number of calculation passes for standalone grid calculator (default: 1)
  • CALC_DELAY_MS - Delay between calculator cycles in milliseconds (default: 0)

Example - Run a specific bot with custom polling interval:

BOT_NAME=my-bot RUN_LOOP_MS=3000 node dexbot.js

๐Ÿ”„ How It Works

  1. Grid Creation: Generates buy/sell orders in geometric progression.
  2. Order Sizing: Applies weight distribution for optimal capital allocation.
  3. Activation: Converts virtual orders to active state.
  4. Rebalancing: Creates new orders from filled positions.
  5. Spread Control: Adds extra orders if the spread becomes too wide.

๐Ÿ“ Order Calculation

The order sizing follows a compact formula:

y = (1-c)^(x*n) = order size

Definitions:

  • c = increment (price step)
  • x = order number (layer index; 0 is closest to market)
  • n = weight distribution (controls how sizes scale across grid)

Weight distribution examples (set n via weightDistribution):

  • -1 = Super Valley (aggressive concentration towards the edge)
  • 0 = Valley (orders increase linearly towards edge)
  • 0.5 = Neutral (balanced distribution)
  • 1 = Mountain (order increase linearly towards center)
  • 2 = Super Mountain (aggressive concentration towards center)

Output Example

===== ORDER GRID =====
Price           Type            State           Size
-----------------------------------------------
160000.00       sell            virtual         0.00555174
...orders...
40814.98        buy             virtual         386.55406154

===== FUNDS STATUS =====
Available: Buy 0.00 USD | Sell 0.00000000 BTC
Committed: Buy 8676.13 USD | Sell 0.12420407 BTC

๐Ÿ” Advanced Features

โš›๏ธ Atomic Updates & Partial Order State Management

DEXBot handles filled orders and partial fills with atomic transactions across all operations:

  • Partial Fills: Remaining portion tracked in PARTIAL state instead of cancellation
  • Atomic Moves: Partial orders moved to new price levels in single transaction
  • Fill Detection: Automatically detects filled orders via blockchain history or open orders snapshot
  • State Synchronization: Grid state immediately reflects filled orders, proceeds credited to available funds
  • Batch Execution: All updates submitted as single atomic operation (creates + updates + cancellations)
  • Consistency Guarantee: Either all operations succeed or all fail - no partial blockchain states
  • No Manual Intervention: Fully automatic fill processing, state updates, and rebalancing

This comprehensive fill handling ensures capital efficiency, eliminates orphaned orders or stuck funds, and guarantees consistency across all order state changes.

โฑ๏ธ Fill Deduplication

Fills are tracked with a 5-second deduplication window to prevent duplicate order processing. This ensures reliable fill detection even if the same fill event arrives multiple times.

๐Ÿ”ข Price Tolerance & Integer Rounding

The bot calculates price tolerances to account for blockchain integer rounding discrepancies. This ensures reliable matching of on-chain orders with grid orders despite minor precision differences.

๐Ÿ’พ Persistent Grid & Price Caching

DEXBot intelligently caches grid calculations and order prices to avoid unnecessary recalculation:

  • Grid state persists in profiles/orders.json across bot restarts
  • Order prices preserved from the last successful synchronization
  • No recalculation on startup if grid matches on-chain state
  • Automatic resync only when on-chain state differs (fills, cancellations)

This optimization significantly reduces startup time and blockchain queries, especially for bots running 20+ orders.

๐Ÿ“ฑ Offline Filled Order Detection

The bot automatically detects orders that were filled while offline:

  • Compares persisted grid with current on-chain open orders on startup
  • Identifies missing orders (orders from grid that are no longer on-chain)
  • Marks them as FILLED and credits proceeds to available funds
  • Immediate rebalancing - replaces filled orders on next cycle
  • No manual intervention needed - fully automatic synchronization

This ensures seamless resumption after being offline without missing fill proceeds.

๐Ÿ“Œ Trigger-File Grid Regeneration

Create a trigger file profiles/recalculate.<bot-key>.trigger to request immediate grid regeneration on the next polling cycle. This allows external scripts to request recalculation without restarting the bot.

Example:

touch profiles/recalculate.my-bot.trigger

๐Ÿงฎ Standalone Grid Calculator

Use the standalone calculator to dry-run grid calculations without blockchain interaction:

# Calculate grid 5 times with 1-second delays
CALC_CYCLES=5 CALC_DELAY_MS=1000 BOT_NAME=my-bot node -e "require('./modules/order/runner').runOrderManagerCalculation()"

Environment variables:

  • BOT_NAME or LIVE_BOT_NAME - Select bot from profiles/bots.json
  • CALC_CYCLES - Number of calculation passes (default: 1)
  • CALC_DELAY_MS - Delay between cycles in milliseconds (default: 0)

๐Ÿ“ฆ Modules

Below is a short summary of the modules in this repository and what they provide. You can paste these lines elsewhere if you need a quick reference.

๐Ÿš€ Entry Points

  • dexbot.js: Main CLI entry point. Handles single-bot mode (start, stop, restart, drystart) and management commands (keys, bots, --cli-examples). Includes full DEXBot class with grid management, fill processing, and account operations.
  • pm2.js: Unified PM2 launcher. Orchestrates BitShares connection, PM2 check/install, ecosystem config generation from profiles/bots.json, master password authentication, and bot startup with automatic restart policies.
  • bot.js: PM2-friendly per-bot entry point. Loads bot config by name from profiles/bots.json, authenticates via master password (from environment or interactive prompt), initializes DEXBot instance, and runs the trading loop.

๐Ÿ”ง Core Modules

  • modules/account_bots.js: Interactive editor for bot configurations (profiles/bots.json). Prompts accept numbers, percentages and multiplier strings (e.g. 5x).
  • modules/chain_keys.js: Encrypted master-password storage for private keys (profiles/keys.json), plus key authentication and management utilities.
  • modules/chain_orders.js: Account-level order operations: select account, create/update/cancel orders, listen for fills with deduplication, read open orders. Uses 'history' mode for fill processing which matches orders from blockchain events.
  • modules/bitshares_client.js: Shared BitShares client wrapper and connection utilities (BitShares, createAccountClient, waitForConnected).
  • modules/btsdex_event_patch.js: Runtime patch for btsdex library to improve history and account event handling.
  • modules/account_orders.js: Local persistence for per-bot order-grid snapshots and metadata (profiles/orders.json).

๐Ÿ“Š Order Subsystem (modules/order/)

Core order generation, management, and grid algorithms:

  • modules/order/constants.js: Order constants, grid limits, and DEFAULT_CONFIG.
  • modules/order/index.js: Public entry point: exports OrderManager and runOrderManagerCalculation() (dry-run helper).
  • modules/order/logger.js: Colored console logger and logOrderGrid() helper for formatted output.
  • modules/order/manager.js: OrderManager class โ€” derives market price, resolves bounds, builds and manages the grid, handles fills and rebalancing.
  • modules/order/grid.js: Grid generation algorithms, order sizing, weight distribution, and minimum size validation.
  • modules/order/runner.js: Runner for calculation passes and dry-runs without blockchain interaction.
  • modules/order/utils.js: Utility functions (percent parsing, multiplier parsing, blockchain float/int conversion, market price helpers).

๐Ÿค Contributing

  1. Fork the repository
  2. Create a feature branch
  3. Make your changes
  4. Test thoroughly
  5. Submit a pull request

๐Ÿ“„ License

MIT License - see LICENSE file for details

๐Ÿ”— Links

  • Telegram
  • Website
  • Ask DeepWiki
  • Awesome BitShares
  • Reddit

About

Rewrite and optimize the staggered order strategy for market making in JavaScript on BitShares.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • JavaScript 97.9%
  • Shell 2.1%