Skip to content

Stateless, deterministic, no-risk spot-exchange emulator for testing and debugging trading bots — fake losses, real skills.

License

Notifications You must be signed in to change notification settings

didac-crst/mockexchange

Repository files navigation

MockExchange Suite

Python License: MIT Docker Poetry Tests Status Code Quality Code style: ruff Type checking: mypy CodeRabbit Pull Request Reviews

Trade without fear, greed, or actual money — because every fake loss is a real step up.

This repository contains the full MockExchange paper-trading platform:

  • MockX Engine – Matching engine, portfolio tracking, and API layer.
  • MockX Periscope – Streamlit-based dashboard for visualizing portfolio and orders.
  • MockX Oracle – Price feed service (e.g., Binance via CCXT → Valkey).
  • MockX Gateway* (external repo) – Lightweight Python wrapper for the MockX Engine API, providing a ccxt-style interface for bots and scripts.

Table of Contents


TL;DR

  • Stateless, deterministic, no-risk spot-exchange emulator.
  • ccxt-compatible API — test bots without touching live markets.
  • Externalized price feed (MockX Oracle) so you can swap sources.
  • Companion Streamlit dashboard (MockX Periscope) for monitoring.
  • Full CLI + REST API + Docker support.

📜 Story

It was 2013, and Bitcoin had just hit a jaw-dropping $300. Someone in our old engineering WhatsApp group brought it up. I asked innocently, “What’s that?”

The response came instantly, dripping with confidence: “You’re too late — this bubble is about to burst…”

Which, in hindsight, was probably the most confidently wrong (and overly cautious) financial advice I’ve ever received.

But something about it intrigued me. I didn’t fully understand it. I didn’t even think it would work — and yet, I bought in. Just 2/3 of a BTC, about 180 €, which, at the time, I mentally wrote off as “money I’ll never see again.” Spoiler: it was the best terrible financial decision I’ve ever made.

I held. And held. And held some more.

Then came 2017 — the year of Lambos, moon memes, and FOMO-induced insomnia. I began checking prices at night before bed, and again first thing in the morning — not for fun, but to confirm whether I was now rich… or still stuck working 9 to 5.

This, of course, led me to the classic rookie move: diversification. I dove into altcoins with names like LTC, TROY, and others I’ve repressed like a bad haircut from high school. Let’s just say: they didn’t go to the moon — they dug a tunnel.

Decision after decision, I watched my gains evaporate in slow motion. Eventually, I realized I needed support — not from a financial advisor (they’d only remind me of my poor decisions), but from something more aligned with my goals — not theirs.

Something logical. Emotionless. Free from fear and greed. Unimpressed by sudden price spikes or Twitter hype. A system that won’t panic sell or chase pumps.

I wanted an intelligent system that could make decisions based on data, not dopamine. Something that would just execute the plan, no matter how boring or unsexy that plan was. Something more disciplined than I’d ever been — able to stay locked on a single task for hours, without fatigue, distraction, or the urge to check the news.

In short, I wanted to build a trader with no feelings — like a psychopath, but helpful.

So in 2020, full of optimism and free time, I enrolled in an AI-for-trading program. I was ready to automate the pain away.

Then… I became a dad.

Suddenly, my trading ambitions were replaced with diapers, sleep deprivation, and learning the fine art of negotiating with toddlers. Needless to say, the bot went on standby — alongside my hobbies, ambitions, and most adult-level reasoning.

Fast forward to 2024. The kids sleep (sometimes), and my curiosity roared back to life. I decided it was time to build — for real. Not to get rich — but because this is what I do for fun: connect dots, explore computer science, study markets, and challenge my past self with fewer emotional trades and more intelligent systems.

But ideas need hardware. So I bought my first Raspberry Pi. Because if I was going to burn time, I wasn’t about to burn kilowatts. I needed something that could run 24/7 without turning my electricity bill into a second mortgage. Resilient, quiet, efficient — like a monk with a TPU, ready to meditate on market patterns in silence for as long as it takes. It wasn’t much, but it was enough to get started.

From there, the system began to grow — and spiral. Scraping prices in real time, keeping databases efficient, aggregating data, archiving old data, writing little scripts that somehow become immortal zombie processes needing to be killed by hand... I genuinely didn’t expect it to be so much.

And yet — I like it. This is how I relax: designing systems no one asked for, solving problems I created myself, and picking up strange new skills in the process — the kind you never set out to learn, but somehow end up mastering.

Which brings us to 2025, and MockExchange: a stateless, deterministic, no-risk spot-exchange emulator that speaks fluent ccxt, pretends it’s real, and stores the last price-tick, balance and order in Valkey (aka Redis) — instead of touching live markets — so you can test, dry-run, and debug your bot without risking a single satoshi.

No more fear. No more “should I have bought?” or “why did I sell?” Just logic, fake orders, and enough tooling to safely build the thing that trades smarter than I did.


✨ Core Features

  • 🧩 Modular architecture — Engine, Periscope, Oracle, and Gateway can run independently or together.
  • 🔌 Pluggable components — swap price feeds, dashboards, or clients without touching the core.
  • 🌐 ccxt-inspired interface — follows familiar trading API patterns to simplify bot integration.
  • 📊 Full visibility — Periscope dashboard for live monitoring of balances, orders, and performance metrics.
  • 🔮 Realistic market simulation — Oracle injects live exchange prices into a safe, risk-free trading environment.
  • 🚀 Ready for production — Dockerized services with pinned versions, path-filtered CI, and clear interface boundaries.
  • 🛠 Developer-friendly — One-command setup, pre-commit hooks, comprehensive testing, and linting.

🗺 Architecture & Ecosystem

flowchart TB
    subgraph Clients
        periscope["MockX Periscope<br/>(Streamlit UI)"]
        bot["Trading Bot / Script"]
    end

    subgraph Infra
        redis[("Valkey / Redis")]
        engine["MockX Engine 📈"]
    end

    subgraph External
        binance["Binance (Live Market Data)"]
    end

    bot -->|ccxt-like wrapper| gateway["MockX Gateway 🛡 (external)"]
    periscope -->|HTTP/REST| engine
    gateway -->|HTTP/REST| engine

    engine --> redis

    oracle["MockX Oracle 🔮<br/>(ccxt → Redis)"] --> redis
    binance -->|ccxt| oracle

    %% Color styling for important components
    style engine fill:#1976d2,color:#ffffff
    style periscope fill:#7b1fa2,color:#ffffff
    style oracle fill:#388e3c,color:#ffffff
    style redis fill:#f57c00,color:#ffffff
    style gateway fill:#d32f2f,color:#ffffff
Loading

📦 Packages in this Monorepo

Package Path Description README
MockX Valkey packages/valkey/ Redis-compatible database for data persistence. Valkey README
MockX Oracle packages/oracle/ Market data feeder (ccxt → Valkey/Redis). Oracle README
MockX Engine packages/engine/ Core engine (core/), API layer (api/), CLI tools. Engine README
MockX Periscope packages/periscope/ Streamlit dashboard for portfolio and orders. Periscope README

Related (external):


🚀 Quick Start

Prerequisites

  • Docker and Docker Compose installed
  • Git for cloning the repository

1. Clone and Setup

# Clone the repository
git clone https://github.com/your-username/mockexchange.git
cd mockexchange

# Setup environment (first time only)
cp .env.example .env
# Edit .env if needed (defaults work for most cases)

2. Start All Services

# Start all services in parallel (default)
make start

# Or start services in dependency order (recommended for first-time setup)
make start-sequential

What this launches:

  • MockX Valkey (Redis-compatible database) on port 6379
  • MockX Oracle (price feed service)
  • MockX Engine (trading API) on port 8000
  • MockX Periscope (dashboard) on port 8501

3. Access Your Services

Alternative: Manual Service Management

If you prefer to start services individually or connect to external services:

# Start services in order (recommended)
make start-valkey      # Database first
make start-oracle      # Price feed
make start-engine      # Trading API
make start-periscope   # Dashboard

# Or stop/restart individual services
make stop-engine       # Stop only the API
make restart-oracle    # Restart price feed
make logs-periscope    # View dashboard logs

# Connect to external services (update .env first)
# VALKEY_HOST=192.168.1.100
# API_URL=http://192.168.1.101:8000
make start-engine      # Engine connects to external Valkey
make start-periscope   # Periscope connects to external Engine

Development Setup

For contributors and developers:

# 🚀 Complete Development Cycle (Recommended)
make dev              # Install deps + format + lint + type-check + test

# 🧪 Testing
make test             # Run all unit tests
make test-integration # Run integration tests (requires running services)
make integration      # Fresh restart + integration tests (no cache)
make integration-full # Full dev cycle + integration tests

# 🔧 Code Quality
make format           # Format code with Ruff
make lint             # Run linting with Ruff
make type-check       # Run type checking with MyPy (smart filtering)

# 🐳 Service Management
make start            # Start all services
make stop             # Stop all services
make restart          # Restart all services
make restart-no-cache # Restart with fresh builds (no cache)
make status           # Show service status

# 📊 Logs
make logs             # All service logs
make logs-engine      # Engine logs only
make logs-oracle      # Oracle logs only
make logs-periscope   # Dashboard logs only
make logs-valkey      # Database logs only

# 🏷️ Release Management
make release-branch   # Create release branch (interactive)
make version          # Show current version and tags

# 🔗 GitHub PR Tools
make export-pr-comments PR=123  # Export PR comments to JSON for LLM analysis
make analyze-pr-comments PR=123 # Analyze all comments and generate LLM prompt
make analyze-pr-comments-latest PR=123 # Analyze only latest review (recommended)
make export-and-analyze-pr PR=123 # Export and analyze all comments in one command
make export-and-analyze-pr-latest PR=123 # Export and analyze latest review only (recommended)

make logs-valkey # Database logs only make logs-engine # Engine logs only make logs-oracle # Oracle logs only make logs-periscope # Dashboard logs only

Check service status

make status # Show all service statuses

🎯 Enhanced Development Workflow

The MockExchange development workflow has been enhanced with comprehensive automation:

🚀 One-Command Development Cycle

make dev  # Does everything: install → format → lint → type-check → test
  • Installs dependencies (Poetry + pre-commit)
  • Formats code (Ruff)
  • Runs linting (Ruff)
  • Type checking (MyPy with smart filtering)
  • Runs tests (All unit tests)

🧪 Comprehensive Testing

make integration      # Fresh restart + integration tests
make integration-full # Full dev cycle + integration tests
  • Fresh environment: No cached artifacts
  • Real integration: Tests against running services
  • Complete validation: Perfect for pre-release testing

🔧 Smart Type Checking

make type-check  # MyPy with smart filtering
  • Focuses on business logic (ignores framework limitations)
  • Zero false positives (no framework noise)
  • Catches real type issues in your code

🐳 Service Management

make restart-no-cache  # Fresh builds for debugging
make logs-engine       # Service-specific logs
  • Individual service control
  • Fresh rebuilds when needed
  • Easy log access

🔗 GitHub PR Tools

make export-and-analyze-pr-latest PR=123  # One-shot latest review analysis (recommended)
make export-and-analyze-pr PR=123         # One-shot all reviews analysis
make export-pr-comments PR=123            # Export PR comments to JSON
make analyze-pr-comments-latest PR=123    # Analyze only latest review
make analyze-pr-comments PR=123           # Analyze all reviews
  • Export CodeRabbit comments for AI analysis
  • Latest review focus - Avoid LLM confusion from multiple reviews
  • Organized structure in scripts/github-pr-tools/
  • Cursor integration ready for LLM analysis
  • One-shot workflow for quick analysis
  • Requires GitHub token (set in scripts/github-pr-tools/.env)

Setup:

# Create scripts/github-pr-tools/.env with your GitHub token
echo "GITHUB_TOKEN=your_github_token_here" > scripts/github-pr-tools/.env

# One-shot latest review analysis (recommended - less confusion for LLM)
make export-and-analyze-pr-latest PR=123

# Use with Cursor
# Open scripts/github-pr-tools/output/pr_123_comments_latest_review_llm_prompt.txt in Cursor
# Or copy-paste the content into Cursor's chat

🚀 How we ship

Standard Workflow (Recommended)

  1. Create a feature branch, implement changes.
  2. Open a Pull Request (PR). CI runs tests and lint.
  3. When green, merge into main.
  4. Create a release:
    • GitHub UI (Recommended): ReleasesDraft a new release → Tag vX.Y.Z → Publish
    • CLI:
      git checkout main && git pull --ff-only
      git tag -a vX.Y.Z -m "MockExchange vX.Y.Z"
      git push origin vX.Y.Z

CI will run on the tag to validate the release commit.

Release Branch Workflow (For Complex Releases)

For more control or when you need to freeze changes for QA/testing:

  1. Create feature branch → implement changes
  2. Open PR → CI runs tests
  3. Create release branch (automated):
    # Interactive mode (recommended)
    make release-branch
    
    # Direct mode
    ./scripts/create-release-branch.sh patch    # 0.1.0 → 0.1.1
    ./scripts/create-release-branch.sh minor    # 0.1.0 → 0.2.0
    ./scripts/create-release-branch.sh major    # 0.1.0 → 1.0.0
    
        # Preview what would happen
     ./scripts/create-release-branch.sh patch --dry-run
  4. Push the release branch: git push -u origin release/vX.Y.Z
  5. Tag the release branch: git tag -a vX.Y.Z -m "Release vX.Y.Z"
  6. Push tag: git push origin vX.Y.Z
  7. Merge to main after release is validated

Release Branch Script Features

The scripts/create-release-branch.sh script provides:

  • 🔄 Automatic version calculation - Fetches latest tags and calculates next version
  • ✅ Git validation - Checks branch, working directory, and remote sync
  • 🛡️ Safety features - Dry-run mode, confirmations, error handling
  • 🎨 User-friendly - Colored output, clear instructions, help text
  • 📋 Next steps - Shows what to do after branch creation

Requirements:

  • Must be on main branch (or confirm override)
  • Working directory must be clean
  • Remote tags must be up to date

Examples:

# See what would happen
./scripts/create-release-branch.sh patch --dry-run

# Create a patch release branch
./scripts/create-release-branch.sh patch

# Interactive mode with menu
make release-branch

Quick Reference: Common Release Commands

# Check current version and tags
make version

# Create release branch (interactive)
make release-branch

# Create release branch (direct)
./scripts/create-release-branch.sh patch

# Create and push a tag
git tag -a v0.1.1 -m "Release v0.1.1"
git push origin v0.1.1

# Deploy specific version
VERSION=v0.1.1 docker-compose up -d

When to use Release Branches

Use a release branch when you need to:

  • Freeze changes for QA/testing while main continues development
  • Cherry-pick hotfixes onto a stable release candidate
  • Maintain multiple release lines (e.g., v1.x and v2.x simultaneously)

Default workflow: Tag directly on main for simplicity.

📦 Install from GitHub tags

You can install any service directly from a Git tag:

Oracle

pip install "git+https://github.com/didac-crst/mockexchange.git@vX.Y.Z#subdirectory=packages/oracle"

Engine

pip install "git+https://github.com/didac-crst/mockexchange.git@vX.Y.Z#subdirectory=packages/engine"

Periscope

pip install "git+https://github.com/didac-crst/mockexchange.git@vX.Y.Z#subdirectory=packages/periscope"

Alternatively, clone at a tag and install with Poetry inside each package:

git clone --depth 1 --branch vX.Y.Z git@github.com:didac-crst/mockexchange.git
cd mockexchange/packages/engine && poetry install

Common Use Cases

# Development workflow
make start-valkey      # Start database first
make start-oracle      # Start price feed
make start-engine      # Then start the API
make logs-engine       # Monitor engine logs
make restart-engine    # Restart after code changes

# Debugging specific services
make logs-valkey       # Check database connectivity
make logs-oracle       # Check if price feed is working
make restart-periscope # Restart dashboard if UI is stuck
make status            # See which services are running

# Selective deployment
make start-valkey make start-engine make start-periscope  # Skip oracle if using external data

📚 Examples

The examples/ directory contains tools and examples that demonstrate how to use the MockExchange platform.

Order Generator

A Dockerized tool that generates random orders to test your MockExchange instance:

# Show available examples
make examples

# Show order generator help
make order-generator

# Start the order generator (fresh start with reset)
make order-generator-start-reset

# Start the order generator (start without reset)
make order-generator-start

# Continue without reset
make order-generator-restart

# Continue with reset
make order-generator-restart-reset

# View logs
make order-generator-logs

# Stop the generator
make order-generator-stop

# Check status
make order-generator-status

Manual usage:

# Ensure MockExchange stack is running
make start

# Start the order generator
cd examples/order-generator
cp .env.example .env
# Edit .env with your API settings
./manage.sh start --reset

For more details, see examples/README.md.


🔧 Environment Configuration

All environment variables are centralized in the root .env file. This eliminates duplication and makes configuration management much easier.

Quick Setup

# Copy the template and customize if needed
cp .env.example .env

# For external Valkey server, update VALKEY_HOST in .env:
# VALKEY_HOST=192.168.1.100  # Replace with your Valkey server IP

Note: The .env.example is configured for Docker Compose. For external services, update:

  • VALKEY_HOST - Point to external Valkey/Redis server
  • ENGINE_HOST - Point to external Engine API server
  • PERISCOPE_HOST - Point to external Periscope dashboard server

Key Configuration Sections

Global Configuration

  • VERSION - MockExchange version
  • TEST_ENV - Test environment flag (enables API docs, disables auth)
  • DEBUG - Development mode flag

Valkey (Database)

  • VALKEY_HOST - Database host (default: valkey for Docker, use IP for external)
  • VALKEY_PASSWORD - Database authentication
  • VALKEY_PORT - Database port (default: 6379)

Oracle (Price Feeds)

  • EXCHANGE - Source exchange (binance, coinbase, etc.)
  • SYMBOLS - Trading pairs to monitor
  • INTERVAL_SEC - Price update frequency
  • QUOTES - Quote assets for discovery (comma-separated, e.g., "USDT,EUR")
  • QUOTE - Fallback quote asset if QUOTES is empty (default: USDT)
  • DISCOVER_QUOTES - Enable automatic market discovery (true/false)
  • DISCOVER_LIMIT - Maximum markets per quote asset (0 = unlimited)

Engine (API)

  • ENGINE_HOST - API server host (default: engine for Docker, use IP for external)
  • ENGINE_PORT - API server port (default: 8000)
  • COMMISSION - Trading commission rate
  • API_KEY - Authentication key
  • CASH_ASSET - Default cash/quote asset for the system (default: USDT)
  • TICK_LOOP_SEC - Price-tick scanning interval in seconds (default: 10)
  • PRUNE_EVERY_MIN - How often to prune old data in minutes (default: 60)
  • STALE_AFTER_H - Data considered stale after hours (default: 24)
  • EXPIRE_AFTER_H - Data expires after hours (default: 2)
  • SANITY_CHECK_EVERY_MIN - Sanity check interval in minutes (default: 10)
  • API_TIMEOUT_SEC - API request timeout for CLI in seconds (default: 10)

Engine Order Processing

  • MIN_TIME_ANSWER_ORDER_MARKET - Minimum delay before processing market orders in seconds (default: 1)
  • MAX_TIME_ANSWER_ORDER_MARKET - Maximum delay before processing market orders in seconds (default: 5)
  • SIGMA_FILL_MARKET_ORDER - Slippage simulation for market order fills (default: 0.1)

Periscope (Dashboard)

  • ENGINE_HOST - Engine host for API URL construction (default: engine for Docker, use IP for external)
  • ENGINE_PORT - Engine port for API URL construction (default: 8000)
  • PERISCOPE_HOST - Dashboard host for UI URL construction (default: localhost)
  • PERISCOPE_PORT - Dashboard port for UI URL construction (default: 8501)
  • APP_TITLE - Dashboard title
  • REFRESH_SECONDS - Auto-refresh interval
  • QUOTE_ASSET - Quote asset for portfolio valuation (default: USDT)
  • FRESH_WINDOW_S - Fresh window for highlighting in seconds (default: 60)
  • N_VISUAL_DEGRADATIONS - Number of fade-out levels for visual feedback (default: 60)
  • SLIDER_MIN - Minimum value for order count slider (default: 10)
  • SLIDER_MAX - Maximum value for order count slider (default: 1000)
  • SLIDER_STEP - Step size for order count slider (default: 10)
  • SLIDER_DEFAULT - Default value for order count slider (default: 50)
  • LOCAL_TZ - Timezone for timestamps (default: Europe/Berlin)
  • LOGO_FILE - Logo file for dashboard (optional)

Benefits of Centralized Configuration

  • Single source of truth - All config in one place

  • No duplication - Eliminates scattered .env files

  • Easy customization - Change once, applies everywhere

  • Better security - Centralized password management

  • Simplified deployment - One config file to manage

  • Automatic URL construction - API_URL and UI_URL built from HOST:PORT variables

URL Construction

The system automatically constructs URLs from HOST and PORT variables:

  • API_URL = http://${ENGINE_HOST}:${ENGINE_PORT} (for Periscope to connect to Engine)
  • UI_URL = http://${PERISCOPE_HOST}:${PERISCOPE_PORT} (for dashboard links)

This means you only need to configure the individual HOST and PORT variables, not the full URLs.


🗂 Monorepo Structure

mockexchange/
├── packages/
│   ├── valkey/        # MockX Valkey (Redis database)
│   ├── engine/        # MockX Engine (core/ + api/)
│   ├── periscope/     # MockX Periscope (dashboard)
│   └── oracle/        # MockX Oracle (price feeds)
├── examples/          # Examples and tools
│   ├── order-generator/ # Random order generator
│   └── README.md      # Examples overview
├── .github/workflows/ # CI/CD pipelines
├── docker-compose.yml # Full stack orchestration
├── .env.example       # Environment configuration template
├── Makefile          # Development commands
├── pyproject.toml    # Root workspace config
├── .pre-commit-config.yaml # Code quality hooks
├── scripts/          # Development and release scripts
│   └── create-release-branch.sh # Automated release branch creation
├── CHANGELOG.md      # Version history and release notes
├── DOCKER_VERSIONS.md # Docker version pinning documentation
└── README.md         # This file

📚 Documentation

Core Documentation

Project Documentation

External Resources


🪪 License

This project is licensed under the MIT License - see the LICENSE file for details.

Don’t risk real money. Spin up MockExchange, hammer it with tests, then hit live markets only when your algos are solid.