BAEngine - bid/ask market engine

This repo is reachable at https://github.com/mmirko/baengine.git


A concurrent financial market simulation engine written in Go, designed for modeling and simulating trading activities with agents, securities, and markets.

Overview

BAEngine is a high-performance trading simulation engine that implements a full order matching system with concurrent order processing, portfolio management, and real-time market depth visualization. It provides a framework for simulating multi-agent trading scenarios with limit orders, order books, and automated matching.

Features

  • Concurrent Order Processing: Built with Go’s goroutines and channels for high-performance concurrent operations
  • Multi-Agent Support: Multiple trading agents with individual portfolios
  • Order Book Management: Separate bid and ask books with price-time priority
  • Order Types: Limit orders with buy/sell directions (market orders in development)
  • Portfolio Management: Automatic fund reservation and tracking for each agent
  • Real-time Data Export:
    • JSON depth charts via HTTP API
    • Protocol Buffers export for efficient data serialization
  • Debug Mode: Comprehensive logging for debugging trading scenarios
  • Market Liquidity Tracking: Monitors spread profits and market liquidity

Project Structure

baengine/
├── baengine.go              # Core engine implementation
├── agent.go                 # Agent structure and methods
├── agents.go                # Agent registration and management
├── market.go                # Market structure and trading logic
├── markets.go               # Market registration and management
├── order.go                 # Order types and order list management
├── portfolio.go             # Portfolio management with fund reservation
├── portfolios.go            # Portfolio operations
├── security.go              # Security definition
├── securities.go            # Security registration
├── manager_default.go       # Default order matching algorithm
├── depth_charts.go          # Market depth chart exporters
├── logging.go               # Logging utilities
├── *_test.go                # Test files
├── go.mod                   # Go module definition
└── Makefile                 # Build configuration

frontend/
└── frontend_test.html       # Example visualization with Plotly.js

Installation

Prerequisites

  • Go 1.12 or higher
  • godebug (for conditional debugging information)

Dependencies

go get github.com/golang/protobuf
go get github.com/mmirko/dpt

Usage

Basic Example

package main

import (
    "baengine"
)

func main() {
    // Initialize the engine
    e := new(baengine.BAEngine)
    e.Init()
    
    // Optional: Enable debug mode for detailed logging
    e.SetDebug()
    
    // Register agents
    agent1_id, _ := e.RegisterAgent("Trader1")
    agent2_id, _ := e.RegisterAgent("Trader2")
    
    // Register securities
    sec1_symbol, _ := e.RegisterSecurity("Security 1", "SEC1")
    sec2_symbol, _ := e.RegisterSecurity("Security 2", "SEC2")
    
    // Register market (format: "SECURITY-CURRENCY")
    market_symbol, _ := e.RegisterMarket("Main Market", "SEC1-SEC2")
    
    // Deposit funds to agents
    e.Deposit(agent1_id, sec1_symbol, 1000.0)
    e.Deposit(agent2_id, sec2_symbol, 1000.0)
    
    // Place orders
    // Sell order: agent1 sells 5 units of SEC1 at price 3.0
    oid1, _ := e.Order(agent1_id, baengine.SELL, market_symbol, 
                       baengine.OLIMIT, 5.0, 3.0)
    
    // Buy order: agent2 buys 5 units of SEC1 at price 3.04
    oid2, _ := e.Order(agent2_id, baengine.BUY, market_symbol, 
                       baengine.OLIMIT, 5.0, 3.04)
    
    // View portfolios
    e.DumpPortfolios()
}

Order Types

  • OLIMIT: Limit order with specified price
  • OMARKET: Market order (currently unimplemented)

Order Directions

  • BUY: Buy order
  • SELL: Sell order

Order States

  • SUBMITTED: Order submitted to the market
  • PARTIALLY: Order partially filled
  • COMPLETED: Order fully executed

API Reference

Engine Initialization

e := new(BAEngine)
e.Init()                    // Initialize the engine
e.SetDebug()                // Enable debug logging
e.SetVerbose()              // Enable verbose logging

Agent Management

// Register a new trading agent
agentID, err := e.RegisterAgent(name string) (uint16, error)

// Unregister an agent
agentID, err := e.UnRegisterAgent(agent_id uint16) (uint16, error)

// Get agent by ID
agent, err := e.AgentIndex(agent_id uint16) (*agent, error)

Security Management

// Register a new security
symbol, err := e.RegisterSecurity(name, symbol string) (string, error)

// Unregister a security
symbol, err := e.UnRegisterSecurity(symbol string) (string, error)

// Get security by symbol
security, err := e.SecurityIndex(symbol string) (*security, error)

Market Management

// Register a new market (symbol format: "SEC1-SEC2")
symbol, err := e.RegisterMarket(name, symbol string) (string, error)

// Unregister a market
symbol, err := e.UnRegisterMarket(symbol string) (string, error)

// Get market by symbol
market, err := e.MarketIndex(symbol string) (*market, error)

// Start/stop trading on a market
err := market.StartTrading()
err := market.StopTrading()

Portfolio Operations

// Deposit funds to an agent's portfolio
err := e.Deposit(agent_id uint16, security_symbol string, qty float32)

// Withdraw funds from an agent's portfolio
err := e.Withdrawn(agent_id uint16, security_symbol string, qty float32)

// Display all portfolios
e.DumpPortfolios()

Order Placement

// Place an order
orderID, err := e.Order(
    agent_id uint16,           // Agent placing the order
    direction uint8,           // BUY or SELL
    market_symbol string,      // Market symbol (e.g., "SEC1-SEC2")
    order_type uint8,          // OLIMIT or OMARKET
    quantity float32,          // Order quantity
    price float32              // Order price
) (uint64, error)

Market Depth Visualization

HTTP API

The engine provides an HTTP endpoint for real-time market depth charts:

http.HandleFunc("/market/depthchart/", e.marketJsonDepthChartExporter)
http.ListenAndServe(":3000", nil)

Access depth chart: http://localhost:3000/market/depthchart/SEC1-SEC2

The response is a JSON object with x (prices) and y (cumulative quantities) arrays.

Frontend Example

See frontend/frontend_test.html for a complete example using Plotly.js to visualize market depth in real-time.

<script>
fetch('http://localhost:3000/market/depthchart/SEC1-SEC2')
  .then(response => response.json())
  .then(data => {
    Plotly.restyle('graph', data, [0]);
  });
</script>

Protocol Buffers Export

For high-performance data export:

e.marketProtobufDepthChartExporter(market_symbol, interval_ms, io.Writer)

Order Matching Algorithm

The engine uses a price-time priority matching algorithm:

  1. BUY orders are matched against the ask book:

    • If buy price ≥ ask price, orders are matched
    • Market captures the spread if buy price > ask price
  2. SELL orders are matched against the bid book:

    • If sell price ≤ bid price, orders are matched
    • Market captures the spread if sell price < bid price
  3. Unmatched portions remain in the order book sorted by price priority

Concurrency Model

BAEngine leverages Go’s concurrency primitives for thread-safe operations:

  • Goroutines: Each market, agent portfolio, and registration service runs in its own goroutine
  • Channels: Used for communication between components (order submission, registration, fund reservation)
  • RWMutex: Protects shared data structures (order books, agent lists, portfolios)

Testing

Run tests with the provided Makefile:

make test

Or run specific tests:

go test --run TestAgentRegistration
go test --run TestSecurityRegistration
go test --run TestMarketRegistration
go test --run TestTrading
go test --run TestExport
go test --run TestProtobuf

Clean up generated debug files:

make clean

Debug Mode

Enable debug mode for detailed execution logging:

e.SetDebug()

Debug logs include:

  • Order submissions and matching details
  • Portfolio reserve requests
  • Order state changes
  • Market liquidity updates
  • Spread profits

The project uses conditional compilation with the GODEBUG build tag to include/exclude debug code.

Architecture

Core Components

  1. BAEngine: Central coordinator managing all components
  2. Agents: Trading entities with unique IDs and portfolios
  3. Securities: Tradable assets identified by symbols
  4. Markets: Order matching venues with bid/ask books
  5. Orders: Trade instructions with quantity, price, and state
  6. Portfolios: Asset tracking with automatic fund reservation

Data Flow

Agent → Order Request → Market → Order Matching → Portfolio Update
                                ↓
                          Order Book (Bid/Ask)
                                ↓
                          Depth Chart Export

Performance Considerations

  • Order matching is performed sequentially within each market but markets operate concurrently
  • Portfolio operations use channel-based reservation to prevent race conditions
  • Order books use linked lists for efficient insertion/removal
  • Read-write mutexes allow concurrent reads of order books for depth chart export

Limitations

  • Market orders are not yet implemented
  • No order cancellation functionality
  • No stop-loss or conditional order types
  • Markets must be in “accepting” state to receive orders
  • Trading must be started explicitly on each market

Future Enhancements

Potential areas for expansion:

  • Market order implementation
  • Order cancellation and modification
  • Stop-loss and take-profit orders
  • Historical trade data export
  • Advanced order matching algorithms
  • WebSocket support for real-time updates
  • More sophisticated market makers
  • Multi-market order routing

License

This project is hosted at https://github.com/mmirko/baengine.

Contributing

When contributing, please:

  1. Run tests before submitting changes
  2. Follow Go best practices and formatting (gofmt)
  3. Add tests for new functionality
  4. Update documentation as needed
  5. Use the debug build tag for debugging code

Note: This is a simulation engine designed for research and educational purposes. It is not intended for production trading systems.