SECTION 1: LEARNING OBJECTIVES

By the end of this lesson, you will be able to:

  • Define digital asset exchanges and their role in the ecosystem.

  • Differentiate between Centralised Exchanges (CEX) and Decentralised Exchanges (DEX).

  • Explain order book mechanics and matching engines.

  • Understand Automated Market Makers (AMMs) and liquidity pools.

  • Describe trading types (spot, margin, futures, options).

  • Identify security and regulatory considerations for exchanges.

  • Implement a simplified exchange simulation in Python.

  • Develop a framework for evaluating exchange platforms.


SECTION 2: WHAT IS A DIGITAL ASSET EXCHANGE?

2.1 Definition

digital asset exchange is a platform that facilitates the trading of cryptocurrencies and digital assets. It connects buyers and sellers, provides price discovery, and enables the transfer of assets between participants.

2.2 Exchange Types

text
┌─────────────────────────────────────────────────────────────────────────────┐
│                    DIGITAL ASSET EXCHANGE TYPES                             │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  CENTRALISED EXCHANGE (CEX)                                                │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │ • Operated by a centralised company                                 │   │
│  │ • Custodial (holds user funds)                                      │   │
│  │ • High liquidity and speed                                          │   │
│  │ • Examples: Binance, Coinbase, Kraken, Bybit                       │   │
│  │ • Pros: User-friendly, deep liquidity, customer support           │   │
│  │ • Cons: Custodial risk, hacks, regulatory scrutiny                │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
│  DECENTRALISED EXCHANGE (DEX)                                              │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │ • Operated by smart contracts                                       │   │
│  │ • Non-custodial (users hold own funds)                             │   │
│  │ • Lower liquidity (but growing)                                    │   │
│  │ • Examples: Uniswap, SushiSwap, Curve, dYdX                       │   │
│  │ • Pros: Non-custodial, transparent, permissionless                │   │
│  │ • Cons: Slippage, impermanent loss, limited features              │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
│  HYBRID EXCHANGE                                                           │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │ • Combines CEX and DEX features                                     │   │
│  │ • On-chain settlement with off-chain order books                   │   │
│  │ • Examples: dYdX, GMX, Hashflow                                   │   │
│  │ • Pros: Speed of CEX, security of DEX                             │   │
│  │ • Cons: Complexity, still evolving                                 │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

SECTION 3: CENTRALISED EXCHANGES (CEX)

3.1 Exchange Architecture

text
┌─────────────────────────────────────────────────────────────────────────────┐
│                    CEX ARCHITECTURE                                         │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  USER INTERFACE                                                             │
│       │                                                                     │
│       v                                                                     │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                    API GATEWAY                                       │   │
│  │  • Authentication                                                     │   │
│  │  • Rate limiting                                                      │   │
│  │  • Request routing                                                    │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                    │                                        │
│                     ┌──────────────┼──────────────┐                       │
│                     v              v              v                       │
│  ┌──────────────────┐  ┌──────────────────┐  ┌──────────────────┐        │
│  │   Order Book     │  │  Matching Engine  │  │  Trade Database  │        │
│  │   • Buy orders   │  │  • Order matching │  │  • Trade history │        │
│  │   • Sell orders  │  │  • Trade execution│  │  • Balances     │        │
│  │   • Order depth  │  │  • Fee calculation│  │  • User data    │        │
│  └──────────────────┘  └──────────────────┘  └──────────────────┘        │
│                     │              │              │                       │
│                     └──────────────┼──────────────┘                       │
│                                    v                                        │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                    WALLET & CUSTODY SYSTEM                           │   │
│  │  • Hot wallet (for active trading)                                  │   │
│  │  • Cold storage (for long-term holdings)                            │   │
│  │  • Withdrawal processing                                            │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

3.2 Order Book Mechanics

 
 
Order Type Description Example
Market Order Execute immediately at best available price Buy 1 BTC at market price
Limit Order Execute at specified price or better Buy 1 BTC at $60,000
Stop Order Trigger market order at a stop price Sell at $58,000 stop
Stop-Limit Order Trigger limit order at a stop price Sell limit at $58,500 triggered at $58,000

3.3 Key CEX Metrics

 
 
Metric Description
Trading Volume Total value traded (24h, 30d)
Order Book Depth Liquidity available at different price levels
Number of Pairs Available trading pairs
Fee Structure Maker/taker fees
Number of Users Active users and total accounts

SECTION 4: DECENTRALISED EXCHANGES (DEX)

4.1 DEX Architecture

text
┌─────────────────────────────────────────────────────────────────────────────┐
│                    DEX ARCHITECTURE                                          │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  USER WALLET (MetaMask, etc.)                                              │
│       │                                                                     │
│       v                                                                     │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                    DEX SMART CONTRACTS                               │   │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐              │   │
│  │  │  Factory     │  │  Router      │  │  Pool        │              │   │
│  │  │  Contract    │  │  Contract    │  │  Contracts   │              │   │
│  │  └──────────────┘  └──────────────┘  └──────────────┘              │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                    │                                        │
│                                    v                                        │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                    LIQUIDITY POOLS                                   │   │
│  │  • Pool 1: ETH/USDC                                                 │   │
│  │  • Pool 2: WBTC/USDC                                                │   │
│  │  • Pool 3: DAI/USDC                                                 │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                    │                                        │
│                                    v                                        │
│  ┌──────────────────────────────────────────────────────────────────────┐   │
│  │                    PRICE ORACLES                                     │   │
│  │  • Uniswap TWAP                                                      │   │
│  │  • Chainlink Price Feeds                                            │   │
│  └──────────────────────────────────────────────────────────────────────┘   │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘

4.2 AMM Models

 
 
Model Formula Example Best For
Constant Product x × y = k Uniswap V2 General trading
Constant Sum x + y = k (Rare) Stable pairs
Constant Mean Weighted product Balancer Multi-token pools
StableSwap Hybrid (sum + product) Curve Stablecoin trading
Concentrated Liquidity Range-bound Uniswap V3 Capital efficiency

4.3 Slippage and Impermanent Loss

Slippage: Difference between expected and actual price due to pool size and trade size.

  • Higher trade size vs pool size = higher slippage.

Impermanent Loss: Temporary loss incurred by liquidity providers when pool prices change relative to holding assets.

  • Example: ETH price doubles, IL ~5.7% for 2x price change.


SECTION 5: TRADING TYPES

 
 
Trading Type Description Risk Level Use Case
Spot Trading Buy/sell for immediate delivery Low-Medium Investing, trading
Margin Trading Trade with borrowed funds High Leveraged positions
Futures Contracts for future delivery High Hedging, speculation
Options Right to buy/sell at specified price Medium-High Hedging, income
Perpetuals Futures without expiry High Leverage trading

SECTION 6: IMPLEMENTATION IN PYTHON

python
# ===================================================================
# MODULE 2, LESSON 5: DIGITAL ASSET EXCHANGES
# ===================================================================

import time
import json
import random
from typing import Dict, List, Optional, Tuple
from dataclasses import dataclass
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import warnings
warnings.filterwarnings('ignore')

print("="*70)
print("DIGITAL ASSET EXCHANGES")
print("="*70)

# ----------------------------------------------------------------
# PART A: ORDER BOOK SIMULATION (CEX)
# ----------------------------------------------------------------

print("\n" + "-"*60)
print("PART A: Centralised Exchange Order Book Simulation")
print("-"*60)

@dataclass
class Order:
    id: str
    user: str
    side: str  # 'buy' or 'sell'
    price: float
    amount: float
    order_type: str  # 'limit' or 'market'
    timestamp: float
    
    @property
    def value(self) -> float:
        return self.price * self.amount

class OrderBook:
    def __init__(self, base_asset: str, quote_asset: str):
        self.base_asset = base_asset
        self.quote_asset = quote_asset
        self.buy_orders: List[Order] = []  # Sorted by price DESC
        self.sell_orders: List[Order] = []  # Sorted by price ASC
        self.trades: List[Dict] = []
        self.order_id_counter = 0
    
    def _generate_order_id(self) -> str:
        self.order_id_counter += 1
        return f"ORD-{self.order_id_counter:06d}"
    
    def add_order(self, user: str, side: str, price: float, amount: float, order_type: str = 'limit') -> str:
        order = Order(
            id=self._generate_order_id(),
            user=user,
            side=side,
            price=price,
            amount=amount,
            order_type=order_type,
            timestamp=time.time()
        )
        
        if side == 'buy':
            self.buy_orders.append(order)
            # Sort buy orders DESC
            self.buy_orders.sort(key=lambda x: x.price, reverse=True)
        else:
            self.sell_orders.append(order)
            # Sort sell orders ASC
            self.sell_orders.sort(key=lambda x: x.price)
        
        return order.id
    
    def match_orders(self) -> List[Dict]:
        matched_trades = []
        
        while self.buy_orders and self.sell_orders:
            best_buy = self.buy_orders[0]
            best_sell = self.sell_orders[0]
            
            # Check if buy price >= sell price
            if best_buy.price >= best_sell.price:
                # Match at sell price (or buy price? Exchange determines)
                trade_price = best_sell.price
                trade_amount = min(best_buy.amount, best_sell.amount)
                
                # Record trade
                trade = {
                    'buyer': best_buy.user,
                    'seller': best_sell.user,
                    'price': trade_price,
                    'amount': trade_amount,
                    'value': trade_price * trade_amount,
                    'timestamp': time.time()
                }
                matched_trades.append(trade)
                self.trades.append(trade)
                
                # Update orders
                best_buy.amount -= trade_amount
                best_sell.amount -= trade_amount
                
                # Remove filled orders
                if best_buy.amount <= 0:
                    self.buy_orders.pop(0)
                if best_sell.amount <= 0:
                    self.sell_orders.pop(0)
            else:
                break
        
        return matched_trades
    
    def get_current_price(self) -> Optional[float]:
        if self.buy_orders and self.sell_orders:
            return (self.buy_orders[0].price + self.sell_orders[0].price) / 2
        return None
    
    def get_market_depth(self) -> Dict:
        return {
            'bids': [(o.price, o.amount) for o in self.buy_orders[:5]],
            'asks': [(o.price, o.amount) for o in self.sell_orders[:5]]
        }
    
    def get_metrics(self) -> Dict:
        return {
            'buy_orders': len(self.buy_orders),
            'sell_orders': len(self.sell_orders),
            'trades': len(self.trades),
            'current_price': self.get_current_price(),
            'total_buy_value': sum(o.value for o in self.buy_orders),
            'total_sell_value': sum(o.value for o in self.sell_orders)
        }

# Create exchange
exchange = OrderBook("BTC", "USD")

print("Order Book Simulation:")
print("Add orders:")
exchange.add_order("Alice", 'buy', 60000, 1.5)
exchange.add_order("Bob", 'buy', 59900, 0.5)
exchange.add_order("Charlie", 'buy', 60100, 2.0)
exchange.add_order("David", 'sell', 60200, 1.0)
exchange.add_order("Eve", 'sell', 60300, 0.5)
exchange.add_order("Frank", 'sell', 59800, 1.0)

print("\n--- Matching ---")
trades = exchange.match_orders()
if trades:
    print(f"Trades executed: {len(trades)}")
    for trade in trades:
        print(f"  {trade['buyer']} bought {trade['amount']:.4f} BTC at ${trade['price']:.2f}")
else:
    print("No trades matched")

print("\n--- Market Depth ---")
depth = exchange.get_market_depth()
print("Bids (Buy Orders):")
for price, amount in depth['bids']:
    print(f"  ${price:.2f}: {amount:.4f} BTC")
print("Asks (Sell Orders):")
for price, amount in depth['asks']:
    print(f"  ${price:.2f}: {amount:.4f} BTC")

print("\n--- Metrics ---")
metrics = exchange.get_metrics()
for k, v in metrics.items():
    print(f"  {k}: {v}")

# ----------------------------------------------------------------
# PART B: AMM / DEX SIMULATION (Uniswap-style)
# ----------------------------------------------------------------

print("\n" + "-"*60)
print("PART B: Decentralised Exchange (AMM) Simulation")
print("-"*60)

class AMMExchange:
    def __init__(self, token_a: str, token_b: str, reserve_a: float, reserve_b: float):
        self.token_a = token_a
        self.token_b = token_b
        self.reserve_a = reserve_a
        self.reserve_b = reserve_b
        self.fee = 0.003  # 0.3%
        self.lp_tokens: Dict[str, float] = {}
        self.total_lp_supply = 0
        self.swaps = []
        self.transactions = []
    
    def get_price(self) -> float:
        return self.reserve_b / self.reserve_a
    
    def swap_a_for_b(self, user: str, amount_a: float) -> Optional[float]:
        if amount_a > self.reserve_a:
            print("Insufficient reserve")
            return None
        
        # Apply fee
        amount_a_with_fee = amount_a * (1 - self.fee)
        amount_b_out = self.reserve_b * (amount_a_with_fee / (self.reserve_a + amount_a_with_fee))
        
        self.reserve_a += amount_a
        self.reserve_b -= amount_b_out
        
        self.swaps.append({
            'user': user,
            'direction': f'{self.token_a}{self.token_b}',
            'amount_in': amount_a,
            'amount_out': amount_b_out,
            'timestamp': time.time()
        })
        print(f"Swapped {amount_a:.2f} {self.token_a} for {amount_b_out:.2f} {self.token_b}")
        return amount_b_out
    
    def swap_b_for_a(self, user: str, amount_b: float) -> Optional[float]:
        if amount_b > self.reserve_b:
            print("Insufficient reserve")
            return None
        
        amount_b_with_fee = amount_b * (1 - self.fee)
        amount_a_out = self.reserve_a * (amount_b_with_fee / (self.reserve_b + amount_b_with_fee))
        
        self.reserve_b += amount_b
        self.reserve_a -= amount_a_out
        
        self.swaps.append({
            'user': user,
            'direction': f'{self.token_b}{self.token_a}',
            'amount_in': amount_b,
            'amount_out': amount_a_out,
            'timestamp': time.time()
        })
        print(f"Swapped {amount_b:.2f} {self.token_b} for {amount_a_out:.2f} {self.token_a}")
        return amount_a_out
    
    def add_liquidity(self, user: str, amount_a: float, amount_b: float) -> float:
        current_ratio = self.reserve_a / self.reserve_b
        if amount_a / amount_b != current_ratio:
            # Adjust to maintain ratio
            if amount_a / amount_b > current_ratio:
                amount_a = amount_b * current_ratio
            else:
                amount_b = amount_a / current_ratio
        
        self.reserve_a += amount_a
        self.reserve_b += amount_b
        
        # Mint LP tokens
        lp_amount = amount_a + amount_b  # Simplified
        self.lp_tokens[user] = self.lp_tokens.get(user, 0) + lp_amount
        self.total_lp_supply += lp_amount
        
        print(f"Added liquidity: {amount_a:.2f} {self.token_a}, {amount_b:.2f} {self.token_b}, minted {lp_amount:.2f} LP tokens")
        return lp_amount
    
    def remove_liquidity(self, user: str, lp_amount: float) -> Tuple[float, float]:
        if self.lp_tokens.get(user, 0) < lp_amount:
            print("Insufficient LP tokens")
            return (0, 0)
        
        # Share of pool
        share = lp_amount / self.total_lp_supply
        amount_a_out = self.reserve_a * share
        amount_b_out = self.reserve_b * share
        
        self.reserve_a -= amount_a_out
        self.reserve_b -= amount_b_out
        self.lp_tokens[user] -= lp_amount
        self.total_lp_supply -= lp_amount
        
        print(f"Removed liquidity: {amount_a_out:.2f} {self.token_a}, {amount_b_out:.2f} {self.token_b}")
        return (amount_a_out, amount_b_out)
    
    def get_metrics(self) -> Dict:
        return {
            'token_a': self.token_a,
            'token_b': self.token_b,
            'reserve_a': self.reserve_a,
            'reserve_b': self.reserve_b,
            'price': self.get_price(),
            'fee': self.fee,
            'num_lps': len(self.lp_tokens),
            'total_lp': self.total_lp_supply,
            'num_swaps': len(self.swaps)
        }

# Create AMM
amm = AMMExchange("ETH", "USDC", 100, 200000)
print(f"AMM Created: 100 ETH, 200,000 USDC")
print(f"Initial Price: {amm.get_price():.2f} USDC/ETH")

print("\n--- Add Liquidity ---")
amm.add_liquidity("Alice", 50, 100000)
amm.add_liquidity("Bob", 30, 60000)

print("\n--- Swaps ---")
amm.swap_a_for_b("Charlie", 5)  # Sell ETH
amm.swap_b_for_a("David", 5000)  # Buy ETH with USDC

print("\n--- Metrics ---")
metrics = amm.get_metrics()
for k, v in metrics.items():
    print(f"  {k}: {v}")

# ----------------------------------------------------------------
# PART C: EXCHANGE COMPARISON
# ----------------------------------------------------------------

print("\n" + "-"*60)
print("PART C: Exchange Comparison Dashboard")
print("-"*60)

exchange_comparison = pd.DataFrame({
    'Exchange': ['Binance', 'Coinbase', 'Kraken', 'Uniswap', 'dYdX', 'Curve'],
    'Type': ['CEX', 'CEX', 'CEX', 'DEX', 'Hybrid', 'DEX'],
    '24h Volume (B)': [15, 3, 1.5, 2.5, 1.2, 0.8],
    'Pairs': [1400, 250, 350, 'Many', 40, 'Many'],
    'Trading Fee': ['0.1%', '0.5%', '0.16%', '0.3%', '0.05%', '0.04%'],
    'Security Score': [8, 9, 8, 7, 7, 8],
    'Regulated': ['Yes (various)', 'Yes', 'Yes', 'Partial', 'Partial', 'Partial']
})

print(exchange_comparison.to_string(index=False))

# Visualise exchange volumes
fig, ax = plt.subplots(figsize=(10, 5))
ax.bar(exchange_comparison['Exchange'], exchange_comparison['24h Volume (B)'], color='teal', alpha=0.7)
ax.set_ylabel('24h Volume (Billion USD)')
ax.set_title('Exchange Daily Trading Volume Comparison')
ax.grid(True, alpha=0.3)
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig('exchange_volumes.png', dpi=300, bbox_inches='tight')
plt.show()
print("Exchange volume chart saved as 'exchange_volumes.png'")

# ----------------------------------------------------------------
# PART D: TRADING STRATEGY SIMULATION
# ----------------------------------------------------------------

print("\n" + "-"*60)
print("PART D: Simple Trading Strategy Simulation")
print("-"*60)

class TradingSimulator:
    def __init__(self, initial_balance: float):
        self.balance = initial_balance
        self.holdings = 0
        self.trades = []
        self.pnl = []
    
    def execute_buy(self, price: float, amount: float) -> bool:
        cost = price * amount
        if cost > self.balance:
            print(f"Insufficient balance: need {cost:.2f}, have {self.balance:.2f}")
            return False
        self.balance -= cost
        self.holdings += amount
        self.trades.append({
            'type': 'buy',
            'price': price,
            'amount': amount,
            'cost': cost,
            'timestamp': time.time()
        })
        print(f"Bought {amount:.4f} at ${price:.2f}")
        return True
    
    def execute_sell(self, price: float, amount: float) -> bool:
        if amount > self.holdings:
            print(f"Insufficient holdings: have {self.holdings:.4f}, want {amount:.4f}")
            return False
        revenue = price * amount
        self.holdings -= amount
        self.balance += revenue
        self.trades.append({
            'type': 'sell',
            'price': price,
            'amount': amount,
            'revenue': revenue,
            'timestamp': time.time()
        })
        print(f"Sold {amount:.4f} at ${price:.2f}")
        return True
    
    def get_portfolio_value(self, current_price: float) -> float:
        return self.balance + self.holdings * current_price
    
    def get_metrics(self, current_price: float) -> Dict:
        return {
            'balance': self.balance,
            'holdings': self.holdings,
            'portfolio_value': self.get_portfolio_value(current_price),
            'num_trades': len(self.trades),
            'total_buy_cost': sum(t['cost'] for t in self.trades if t['type'] == 'buy'),
            'total_sell_revenue': sum(t['revenue'] for t in self.trades if t['type'] == 'sell')
        }

# Simulate trading with price data
trader = TradingSimulator(10000)
price_series = [2000, 2100, 2050, 2200, 2300, 2250, 2400, 2350, 2500]

print("Trading Simulation:")
for i, price in enumerate(price_series):
    print(f"\nDay {i+1}: Price = ${price:.2f}")
    if price < 2100 and trader.holdings == 0:
        trader.execute_buy(price, 4.0)  # Buy when low
    elif price > 2300 and trader.holdings > 0:
        trader.execute_sell(price, 2.0)  # Sell some when high
    elif price > 2400 and trader.holdings > 0:
        trader.execute_sell(price, trader.holdings)  # Sell all

final_price = price_series[-1]
print(f"\nFinal Portfolio Value: ${trader.get_portfolio_value(final_price):.2f}")
metrics = trader.get_metrics(final_price)
for k, v in metrics.items():
    print(f"  {k}: {v}")

# ----------------------------------------------------------------
# PART E: EXCHANGE SECURITY CHECKLIST
# ----------------------------------------------------------------

print("\n" + "-"*60)
print("PART E: Exchange Security Checklist")
print("-"*60)

security_checklist = {
    "User Security": [
        "Two-factor authentication (2FA)",
        "Withdrawal whitelisting",
        "Anti-phishing codes",
        "Session management"
    ],
    "Platform Security": [
        "Cold storage for majority of funds",
        "Multi-sig wallets",
        "Regular security audits",
        "Bug bounty program"
    ],
    "Operational Security": [
        "DDoS protection",
        "Regular penetration testing",
        "Incident response plan",
        "Data encryption"
    ],
    "Regulatory Compliance": [
        "KYC/AML procedures",
        "Sanctions screening",
        "Transaction monitoring",
        "Regulatory reporting"
    ]
}

for category, items in security_checklist.items():
    print(f"\n{category.upper()}:")
    for item in items:
        print(f"  ✓ {item}")

# ----------------------------------------------------------------
# PART F: SUMMARY AND RECOMMENDATIONS
# ----------------------------------------------------------------

print("\n" + "="*70)
print("PART F: Summary and Recommendations")
print("="*70)

print("""
Digital Asset Exchanges – Key Takeaways:

1. Exchanges facilitate trading of cryptocurrencies and digital assets.
2. Types: CEX (centralised, custodial), DEX (decentralised, non-custodial), Hybrid.
3. CEXs use order books with matching engines for trade execution.
4. DEXs use AMMs with liquidity pools and price algorithms.
5. Trading types: spot, margin, futures, options, perpetuals.
6. Key considerations: security, liquidity, fees, regulation, user experience.
7. Risks: hacks, regulatory changes, slippage, impermanent loss, counterparty risk.

Recommendations:
  - Use CEXs for high liquidity and ease of use.
  - Use DEXs for self-custody and privacy.
  - Store only trading funds on exchanges.
  - Use hardware wallets for long-term storage.
  - Understand fee structures before trading.
  - Enable all security features (2FA, whitelisting).
  - Monitor regulatory developments.
""")