Chapter 6: Cryptocurrency Trading Fundamentals

Haiyue
33min

Chapter 6: Cryptocurrency Trading Fundamentals

Learning Objectives
  • Understand how cryptocurrency exchanges operate
  • Master basic trading operation processes
  • Understand order types and trading fees
  • Learn candlestick charts and fundamental technical analysis

Exchange Operation Mechanism

Centralized Exchange (CEX)

import time
import uuid
from typing import Dict, List, Optional
from enum import Enum
from dataclasses import dataclass
import heapq

class OrderType(Enum):
    MARKET = "market"    # Market order
    LIMIT = "limit"      # Limit order
    STOP = "stop"        # Stop loss order
    STOP_LIMIT = "stop_limit"  # Stop limit order

class OrderSide(Enum):
    BUY = "buy"
    SELL = "sell"

class OrderStatus(Enum):
    PENDING = "pending"
    PARTIAL = "partial"
    FILLED = "filled"
    CANCELLED = "cancelled"

@dataclass
class Order:
    """Order data structure"""
    order_id: str
    user_id: str
    symbol: str
    side: OrderSide
    order_type: OrderType
    amount: float
    price: float
    filled_amount: float = 0.0
    status: OrderStatus = OrderStatus.PENDING
    timestamp: float = None

    def __post_init__(self):
        if self.timestamp is None:
            self.timestamp = time.time()

class MatchingEngine:
    """Order matching engine"""

    def __init__(self, symbol: str):
        self.symbol = symbol
        # Use heaps to maintain order book
        self.buy_orders = []   # Max heap (higher price first)
        self.sell_orders = []  # Min heap (lower price first)
        self.trades = []
        self.last_price = 0.0

    def add_order(self, order: Order) -> List[Dict]:
        """Add order and attempt matching"""
        matches = []

        if order.order_type == OrderType.MARKET:
            matches = self._execute_market_order(order)
        elif order.order_type == OrderType.LIMIT:
            matches = self._execute_limit_order(order)

        return matches

    def _execute_market_order(self, order: Order) -> List[Dict]:
        """Execute market order"""
        matches = []
        remaining_amount = order.amount

        if order.side == OrderSide.BUY:
            # Buy order: match starting from lowest sell price
            while remaining_amount > 0 and self.sell_orders:
                best_sell = heapq.heappop(self.sell_orders)[1]
                match_result = self._match_orders(order, best_sell, remaining_amount)

                if match_result:
                    matches.append(match_result)
                    remaining_amount -= match_result['amount']

                    # If sell order not fully filled, add back to order book
                    if best_sell.filled_amount < best_sell.amount:
                        heapq.heappush(self.sell_orders, (best_sell.price, best_sell))

        else:  # SELL
            # Sell order: match starting from highest buy price
            while remaining_amount > 0 and self.buy_orders:
                best_buy = heapq.heappop(self.buy_orders)[1]
                match_result = self._match_orders(order, best_buy, remaining_amount)

                if match_result:
                    matches.append(match_result)
                    remaining_amount -= match_result['amount']

                    # If buy order not fully filled, add back to order book
                    if best_buy.filled_amount < best_buy.amount:
                        heapq.heappush(self.buy_orders, (-best_buy.price, best_buy))

        # Update order status
        order.filled_amount = order.amount - remaining_amount
        order.status = OrderStatus.FILLED if remaining_amount == 0 else OrderStatus.PARTIAL

        return matches

    def _execute_limit_order(self, order: Order) -> List[Dict]:
        """Execute limit order"""
        matches = []
        remaining_amount = order.amount

        if order.side == OrderSide.BUY:
            # Buy order: only match sell orders at or below limit price
            while remaining_amount > 0 and self.sell_orders:
                if self.sell_orders[0][1].price > order.price:
                    break

                best_sell = heapq.heappop(self.sell_orders)[1]
                match_result = self._match_orders(order, best_sell, remaining_amount)

                if match_result:
                    matches.append(match_result)
                    remaining_amount -= match_result['amount']

                    if best_sell.filled_amount < best_sell.amount:
                        heapq.heappush(self.sell_orders, (best_sell.price, best_sell))

        else:  # SELL
            # Sell order: only match buy orders at or above limit price
            while remaining_amount > 0 and self.buy_orders:
                if -self.buy_orders[0][0] < order.price:
                    break

                best_buy = heapq.heappop(self.buy_orders)[1]
                match_result = self._match_orders(order, best_buy, remaining_amount)

                if match_result:
                    matches.append(match_result)
                    remaining_amount -= match_result['amount']

                    if best_buy.filled_amount < best_buy.amount:
                        heapq.heappush(self.buy_orders, (-best_buy.price, best_buy))

        # If order not fully filled, add to order book
        if remaining_amount > 0:
            order.filled_amount = order.amount - remaining_amount
            order.status = OrderStatus.PARTIAL if order.filled_amount > 0 else OrderStatus.PENDING

            if order.side == OrderSide.BUY:
                heapq.heappush(self.buy_orders, (-order.price, order))
            else:
                heapq.heappush(self.sell_orders, (order.price, order))
        else:
            order.filled_amount = order.amount
            order.status = OrderStatus.FILLED

        return matches

    def _match_orders(self, taker_order: Order, maker_order: Order, max_amount: float) -> Optional[Dict]:
        """Match two orders"""
        # Calculate trade volume (take minimum)
        available_amount = maker_order.amount - maker_order.filled_amount
        trade_amount = min(max_amount, available_amount)

        if trade_amount <= 0:
            return None

        # Trade price uses maker order's price
        trade_price = maker_order.price

        # Update order status
        maker_order.filled_amount += trade_amount
        if maker_order.filled_amount >= maker_order.amount:
            maker_order.status = OrderStatus.FILLED
        else:
            maker_order.status = OrderStatus.PARTIAL

        # Record trade
        trade = {
            "trade_id": str(uuid.uuid4()),
            "symbol": self.symbol,
            "amount": trade_amount,
            "price": trade_price,
            "timestamp": time.time(),
            "taker_order_id": taker_order.order_id,
            "maker_order_id": maker_order.order_id,
            "taker_side": taker_order.side.value,
            "maker_side": maker_order.side.value
        }

        self.trades.append(trade)
        self.last_price = trade_price

        return trade

    def get_order_book(self, depth: int = 10) -> Dict:
        """Get order book"""
        # Buy orders (descending by price)
        buy_orders = sorted([order for _, order in self.buy_orders],
                          key=lambda x: x.price, reverse=True)[:depth]

        # Sell orders (ascending by price)
        sell_orders = sorted([order for _, order in self.sell_orders],
                           key=lambda x: x.price)[:depth]

        return {
            "symbol": self.symbol,
            "bids": [(order.price, order.amount - order.filled_amount) for order in buy_orders],
            "asks": [(order.price, order.amount - order.filled_amount) for order in sell_orders],
            "last_price": self.last_price
        }

class CentralizedExchange:
    """Centralized exchange"""

    def __init__(self, name: str):
        self.name = name
        self.matching_engines: Dict[str, MatchingEngine] = {}
        self.user_balances: Dict[str, Dict[str, float]] = {}
        self.fee_rate = 0.001  # 0.1% fee
        self.order_history: Dict[str, List[Order]] = {}

    def add_trading_pair(self, symbol: str):
        """Add trading pair"""
        self.matching_engines[symbol] = MatchingEngine(symbol)

    def deposit(self, user_id: str, currency: str, amount: float):
        """User deposit"""
        if user_id not in self.user_balances:
            self.user_balances[user_id] = {}

        current_balance = self.user_balances[user_id].get(currency, 0.0)
        self.user_balances[user_id][currency] = current_balance + amount

        print(f"User {user_id} deposited {amount} {currency}")

    def place_order(self, user_id: str, symbol: str, side: OrderSide,
                   order_type: OrderType, amount: float, price: float = 0.0) -> str:
        """Place order"""
        if symbol not in self.matching_engines:
            raise ValueError(f"Trading pair {symbol} does not exist")

        # Check balance
        base_currency, quote_currency = symbol.split('/')

        if side == OrderSide.BUY:
            # Buy order requires quote currency
            required_balance = amount * price if order_type == OrderType.LIMIT else amount * self.get_market_price(symbol)
            available_balance = self.user_balances.get(user_id, {}).get(quote_currency, 0.0)

            if available_balance < required_balance:
                raise ValueError(f"Insufficient balance: requires {required_balance} {quote_currency}")

        else:  # SELL
            # Sell order requires base currency
            available_balance = self.user_balances.get(user_id, {}).get(base_currency, 0.0)

            if available_balance < amount:
                raise ValueError(f"Insufficient balance: requires {amount} {base_currency}")

        # Create order
        order_id = str(uuid.uuid4())
        order = Order(
            order_id=order_id,
            user_id=user_id,
            symbol=symbol,
            side=side,
            order_type=order_type,
            amount=amount,
            price=price
        )

        # Execute order matching
        matching_engine = self.matching_engines[symbol]
        matches = matching_engine.add_order(order)

        # Process match results
        for match in matches:
            self._process_trade(match)

        # Record order history
        if user_id not in self.order_history:
            self.order_history[user_id] = []
        self.order_history[user_id].append(order)

        print(f"Order {order_id} submitted, {len(matches)} trades executed")

        return order_id

    def _process_trade(self, trade: Dict):
        """Process trade execution"""
        symbol = trade["symbol"]
        base_currency, quote_currency = symbol.split('/')
        amount = trade["amount"]
        price = trade["price"]
        volume = amount * price

        # Get taker and maker user IDs
        # In actual implementation, need to retrieve user ID from order
        taker_user = "taker_user"  # Simplified
        maker_user = "maker_user"  # Simplified

        # Calculate fees
        taker_fee = volume * self.fee_rate
        maker_fee = volume * self.fee_rate * 0.5  # Maker gets 50% discount

        print(f"Trade executed: {amount} {base_currency} @ {price} {quote_currency}")
        print(f"Taker fee: {taker_fee} {quote_currency}")
        print(f"Maker fee: {maker_fee} {quote_currency}")

    def get_market_price(self, symbol: str) -> float:
        """Get market price"""
        if symbol in self.matching_engines:
            return self.matching_engines[symbol].last_price or 50000.0  # Default price
        return 0.0

    def get_user_balance(self, user_id: str) -> Dict[str, float]:
        """Get user balance"""
        return self.user_balances.get(user_id, {})

    def get_order_book(self, symbol: str, depth: int = 10) -> Dict:
        """Get order book"""
        if symbol in self.matching_engines:
            return self.matching_engines[symbol].get_order_book(depth)
        return {}

# Exchange demonstration
print("=== Centralized Exchange Demonstration ===")

# Create exchange
exchange = CentralizedExchange("CryptoExchange")
exchange.add_trading_pair("BTC/USDT")

# User deposits
exchange.deposit("user1", "BTC", 1.0)
exchange.deposit("user1", "USDT", 60000.0)
exchange.deposit("user2", "BTC", 2.0)
exchange.deposit("user2", "USDT", 100000.0)

print(f"User 1 balance: {exchange.get_user_balance('user1')}")
print(f"User 2 balance: {exchange.get_user_balance('user2')}")

# Place orders
print(f"\n=== Begin Trading ===")

# User 1 places limit buy order
exchange.place_order("user1", "BTC/USDT", OrderSide.BUY, OrderType.LIMIT, 0.1, 50000.0)

# User 2 places limit sell order
exchange.place_order("user2", "BTC/USDT", OrderSide.SELL, OrderType.LIMIT, 0.05, 49500.0)

# View order book
order_book = exchange.get_order_book("BTC/USDT")
print(f"\nOrder Book:")
print(f"Bids: {order_book.get('bids', [])}")
print(f"Asks: {order_book.get('asks', [])}")
print(f"Last Price: {order_book.get('last_price', 0)}")

Order Types and Trading Strategies

Advanced Order Types

class AdvancedOrderType(Enum):
    """Advanced order types"""
    TRAILING_STOP = "trailing_stop"      # Trailing stop
    ICEBERG = "iceberg"                  # Iceberg order
    TWA = "time_weighted_average"        # Time weighted average
    BRACKET = "bracket"                  # Bracket order

@dataclass
class AdvancedOrder(Order):
    """Advanced order"""
    trigger_price: float = 0.0           # Trigger price
    trail_amount: float = 0.0            # Trail amount
    visible_size: float = 0.0            # Visible size (iceberg order)
    time_in_force: str = "GTC"           # Time in force (GTC/IOC/FOK)
    stop_loss_price: float = 0.0         # Stop loss price
    take_profit_price: float = 0.0       # Take profit price

class TradingStrategy:
    """Trading strategy"""

    def __init__(self, name: str):
        self.name = name
        self.positions: Dict[str, float] = {}
        self.pnl = 0.0
        self.trade_history = []

    def dca_strategy(self, symbol: str, total_amount: float,
                    intervals: int, price_levels: List[float]) -> List[Order]:
        """Dollar Cost Averaging (DCA) strategy"""
        orders = []
        amount_per_order = total_amount / intervals

        for i, price in enumerate(price_levels[:intervals]):
            order = Order(
                order_id=f"dca_{i}_{uuid.uuid4()}",
                user_id="dca_trader",
                symbol=symbol,
                side=OrderSide.BUY,
                order_type=OrderType.LIMIT,
                amount=amount_per_order,
                price=price
            )
            orders.append(order)

        print(f"DCA strategy generated {len(orders)} orders, total investment: {total_amount}")
        return orders

    def grid_trading_strategy(self, symbol: str, center_price: float,
                             grid_size: float, grid_count: int,
                             order_amount: float) -> List[Order]:
        """Grid trading strategy"""
        orders = []

        # Generate buy grid (below center price)
        for i in range(1, grid_count + 1):
            buy_price = center_price - (grid_size * i)
            buy_order = Order(
                order_id=f"grid_buy_{i}_{uuid.uuid4()}",
                user_id="grid_trader",
                symbol=symbol,
                side=OrderSide.BUY,
                order_type=OrderType.LIMIT,
                amount=order_amount,
                price=buy_price
            )
            orders.append(buy_order)

        # Generate sell grid (above center price)
        for i in range(1, grid_count + 1):
            sell_price = center_price + (grid_size * i)
            sell_order = Order(
                order_id=f"grid_sell_{i}_{uuid.uuid4()}",
                user_id="grid_trader",
                symbol=symbol,
                side=OrderSide.SELL,
                order_type=OrderType.LIMIT,
                amount=order_amount,
                price=sell_price
            )
            orders.append(sell_order)

        print(f"Grid strategy generated {len(orders)} orders")
        return orders

    def momentum_strategy(self, price_history: List[float],
                         volume_history: List[float]) -> str:
        """Momentum strategy signal"""
        if len(price_history) < 20:
            return "HOLD"

        # Calculate moving averages
        ma_20 = sum(price_history[-20:]) / 20
        ma_5 = sum(price_history[-5:]) / 5

        # Calculate price momentum
        price_momentum = (price_history[-1] - price_history[-10]) / price_history[-10]

        # Calculate volume momentum
        avg_volume = sum(volume_history[-10:]) / 10
        volume_momentum = volume_history[-1] / avg_volume

        # Strategy logic
        if (ma_5 > ma_20 and price_momentum > 0.02 and volume_momentum > 1.5):
            signal = "BUY"
        elif (ma_5 < ma_20 and price_momentum < -0.02):
            signal = "SELL"
        else:
            signal = "HOLD"

        print(f"Momentum strategy signal: {signal}")
        print(f"  Price momentum: {price_momentum:.2%}")
        print(f"  Volume momentum: {volume_momentum:.2f}")

        return signal

    def arbitrage_opportunity(self, exchange1_price: float,
                            exchange2_price: float,
                            fee_rate: float = 0.002) -> Dict:
        """Arbitrage opportunity analysis"""
        # Calculate price difference
        price_diff = abs(exchange1_price - exchange2_price)
        price_diff_pct = price_diff / min(exchange1_price, exchange2_price)

        # Calculate total fees (buy fee + sell fee + transfer fee)
        total_fee_rate = fee_rate * 2 + 0.001  # Assume 0.1% transfer fee

        # Determine if arbitrage opportunity exists
        profit_margin = price_diff_pct - total_fee_rate

        if profit_margin > 0:
            # Determine arbitrage direction
            if exchange1_price < exchange2_price:
                direction = "Buy on Exchange 1, sell on Exchange 2"
                buy_exchange = "Exchange 1"
                sell_exchange = "Exchange 2"
            else:
                direction = "Buy on Exchange 2, sell on Exchange 1"
                buy_exchange = "Exchange 2"
                sell_exchange = "Exchange 1"

            return {
                "opportunity": True,
                "direction": direction,
                "buy_exchange": buy_exchange,
                "sell_exchange": sell_exchange,
                "price_difference": price_diff,
                "profit_margin": profit_margin,
                "estimated_profit_pct": f"{profit_margin:.2%}"
            }
        else:
            return {
                "opportunity": False,
                "reason": "Arbitrage profit insufficient to cover trading costs"
            }

# Trading strategy demonstration
print("\n=== Trading Strategy Demonstration ===")

strategy = TradingStrategy("Multi-Strategy Bot")

# 1. DCA strategy
print("1. Dollar Cost Averaging (DCA):")
dca_price_levels = [50000, 49000, 48000, 47000, 46000]
dca_orders = strategy.dca_strategy("BTC/USDT", 10000.0, 5, dca_price_levels)

for i, order in enumerate(dca_orders):
    print(f"  Order {i+1}: {order.amount} BTC @ ${order.price}")

# 2. Grid trading strategy
print(f"\n2. Grid Trading Strategy:")
grid_orders = strategy.grid_trading_strategy("BTC/USDT", 50000.0, 1000.0, 3, 0.01)

buy_orders = [o for o in grid_orders if o.side == OrderSide.BUY]
sell_orders = [o for o in grid_orders if o.side == OrderSide.SELL]

print(f"  Buy grid:")
for order in buy_orders:
    print(f"    {order.amount} BTC @ ${order.price}")

print(f"  Sell grid:")
for order in sell_orders:
    print(f"    {order.amount} BTC @ ${order.price}")

# 3. Momentum strategy
print(f"\n3. Momentum Strategy Analysis:")
price_data = [48000, 48500, 49000, 49200, 49800, 50100, 50500, 51000, 51200, 51500,
              51800, 52000, 51800, 51600, 52100, 52500, 52800, 53000, 53200, 53500]
volume_data = [100, 120, 150, 180, 200, 250, 300, 280, 320, 350,
               380, 400, 350, 300, 450, 500, 520, 600, 650, 700]

signal = strategy.momentum_strategy(price_data, volume_data)

# 4. Arbitrage opportunity analysis
print(f"\n4. Arbitrage Opportunity Analysis:")
exchange_prices = [
    ("Binance", 50000),
    ("Coinbase", 50150),
    ("Kraken", 49950)
]

for i in range(len(exchange_prices)):
    for j in range(i+1, len(exchange_prices)):
        ex1_name, ex1_price = exchange_prices[i]
        ex2_name, ex2_price = exchange_prices[j]

        arbitrage = strategy.arbitrage_opportunity(ex1_price, ex2_price)

        if arbitrage["opportunity"]:
            print(f"  {ex1_name} vs {ex2_name}: Arbitrage opportunity!")
            print(f"    {arbitrage['direction']}")
            print(f"    Expected profit: {arbitrage['estimated_profit_pct']}")
        else:
            print(f"  {ex1_name} vs {ex2_name}: No arbitrage opportunity")

Candlestick Charts and Technical Analysis

Candlestick Data Processing

import math
from typing import List, Tuple

@dataclass
class Candlestick:
    """Candlestick data"""
    timestamp: float
    open: float
    high: float
    low: float
    close: float
    volume: float

    @property
    def body_size(self) -> float:
        """Body size"""
        return abs(self.close - self.open)

    @property
    def upper_shadow(self) -> float:
        """Upper shadow length"""
        return self.high - max(self.open, self.close)

    @property
    def lower_shadow(self) -> float:
        """Lower shadow length"""
        return min(self.open, self.close) - self.low

    @property
    def is_bullish(self) -> bool:
        """Is bullish candlestick"""
        return self.close > self.open

    @property
    def is_doji(self) -> bool:
        """Is doji candlestick"""
        return self.body_size <= (self.high - self.low) * 0.1

class TechnicalAnalysis:
    """Technical analysis tools"""

    @staticmethod
    def sma(prices: List[float], period: int) -> List[float]:
        """Simple Moving Average (SMA)"""
        if len(prices) < period:
            return []

        sma_values = []
        for i in range(period - 1, len(prices)):
            avg = sum(prices[i - period + 1:i + 1]) / period
            sma_values.append(avg)

        return sma_values

    @staticmethod
    def ema(prices: List[float], period: int) -> List[float]:
        """Exponential Moving Average (EMA)"""
        if len(prices) < period:
            return []

        ema_values = []
        multiplier = 2 / (period + 1)

        # First EMA value uses SMA
        sma_first = sum(prices[:period]) / period
        ema_values.append(sma_first)

        # Subsequent EMA calculations
        for i in range(period, len(prices)):
            ema = (prices[i] * multiplier) + (ema_values[-1] * (1 - multiplier))
            ema_values.append(ema)

        return ema_values

    @staticmethod
    def rsi(prices: List[float], period: int = 14) -> List[float]:
        """Relative Strength Index (RSI)"""
        if len(prices) < period + 1:
            return []

        gains = []
        losses = []

        # Calculate price changes
        for i in range(1, len(prices)):
            change = prices[i] - prices[i-1]
            if change > 0:
                gains.append(change)
                losses.append(0)
            else:
                gains.append(0)
                losses.append(abs(change))

        rsi_values = []

        # Calculate RSI
        for i in range(period - 1, len(gains)):
            avg_gain = sum(gains[i - period + 1:i + 1]) / period
            avg_loss = sum(losses[i - period + 1:i + 1]) / period

            if avg_loss == 0:
                rsi = 100
            else:
                rs = avg_gain / avg_loss
                rsi = 100 - (100 / (1 + rs))

            rsi_values.append(rsi)

        return rsi_values

    @staticmethod
    def macd(prices: List[float], fast_period: int = 12,
             slow_period: int = 26, signal_period: int = 9) -> Tuple[List[float], List[float], List[float]]:
        """MACD indicator"""
        # Calculate fast and slow EMA
        ema_fast = TechnicalAnalysis.ema(prices, fast_period)
        ema_slow = TechnicalAnalysis.ema(prices, slow_period)

        # Align data length
        start_idx = slow_period - fast_period
        ema_fast = ema_fast[start_idx:]

        # Calculate MACD line
        macd_line = [fast - slow for fast, slow in zip(ema_fast, ema_slow)]

        # Calculate signal line
        signal_line = TechnicalAnalysis.ema(macd_line, signal_period)

        # Calculate histogram
        histogram = []
        signal_start = len(macd_line) - len(signal_line)
        for i in range(len(signal_line)):
            histogram.append(macd_line[signal_start + i] - signal_line[i])

        return macd_line, signal_line, histogram

    @staticmethod
    def bollinger_bands(prices: List[float], period: int = 20,
                       std_multiplier: float = 2) -> Tuple[List[float], List[float], List[float]]:
        """Bollinger Bands"""
        if len(prices) < period:
            return [], [], []

        sma = TechnicalAnalysis.sma(prices, period)
        upper_band = []
        lower_band = []

        for i in range(period - 1, len(prices)):
            price_slice = prices[i - period + 1:i + 1]
            std_dev = math.sqrt(sum((p - sma[i - period + 1]) ** 2 for p in price_slice) / period)

            upper_band.append(sma[i - period + 1] + (std_dev * std_multiplier))
            lower_band.append(sma[i - period + 1] - (std_dev * std_multiplier))

        return sma, upper_band, lower_band

    @staticmethod
    def support_resistance(candlesticks: List[Candlestick], window: int = 20) -> Tuple[List[float], List[float]]:
        """Support and resistance level identification"""
        highs = [c.high for c in candlesticks]
        lows = [c.low for c in candlesticks]

        resistance_levels = []
        support_levels = []

        # Find local highs and lows
        for i in range(window, len(candlesticks) - window):
            # Resistance (local high)
            is_resistance = True
            current_high = candlesticks[i].high

            for j in range(i - window, i + window + 1):
                if j != i and candlesticks[j].high >= current_high:
                    is_resistance = False
                    break

            if is_resistance:
                resistance_levels.append(current_high)

            # Support (local low)
            is_support = True
            current_low = candlesticks[i].low

            for j in range(i - window, i + window + 1):
                if j != i and candlesticks[j].low <= current_low:
                    is_support = False
                    break

            if is_support:
                support_levels.append(current_low)

        return support_levels, resistance_levels

# Technical analysis demonstration
print("\n=== Technical Analysis Demonstration ===")

# Generate simulated price data
import random
base_price = 50000
prices = [base_price]

for i in range(100):
    # Simulate price random walk
    change = random.gauss(0, 500)  # Normal distribution change
    new_price = max(prices[-1] + change, 1000)  # Ensure price is positive
    prices.append(new_price)

print(f"Price data: {len(prices)} data points")
print(f"Price range: ${min(prices):,.0f} - ${max(prices):,.0f}")

# 1. Moving averages
sma_20 = TechnicalAnalysis.sma(prices, 20)
ema_12 = TechnicalAnalysis.ema(prices, 12)

print(f"\nMoving Averages:")
print(f"SMA(20) latest value: ${sma_20[-1]:,.2f}")
print(f"EMA(12) latest value: ${ema_12[-1]:,.2f}")

# 2. RSI indicator
rsi = TechnicalAnalysis.rsi(prices, 14)
current_rsi = rsi[-1]

print(f"\nRSI Indicator:")
print(f"Current RSI: {current_rsi:.2f}")

if current_rsi > 70:
    rsi_signal = "Overbought zone, consider selling"
elif current_rsi < 30:
    rsi_signal = "Oversold zone, consider buying"
else:
    rsi_signal = "Neutral zone"

print(f"RSI signal: {rsi_signal}")

# 3. MACD indicator
macd_line, signal_line, histogram = TechnicalAnalysis.macd(prices)

print(f"\nMACD Indicator:")
print(f"MACD line: {macd_line[-1]:,.2f}")
print(f"Signal line: {signal_line[-1]:,.2f}")
print(f"Histogram: {histogram[-1]:,.2f}")

# MACD signal determination
if len(histogram) >= 2:
    if histogram[-1] > 0 and histogram[-2] <= 0:
        macd_signal = "Golden cross signal, bullish"
    elif histogram[-1] < 0 and histogram[-2] >= 0:
        macd_signal = "Death cross signal, bearish"
    else:
        macd_signal = "No clear signal"
    print(f"MACD signal: {macd_signal}")

# 4. Bollinger Bands
sma_bb, upper_band, lower_band = TechnicalAnalysis.bollinger_bands(prices, 20)
current_price = prices[-1]

print(f"\nBollinger Bands:")
print(f"Upper band: ${upper_band[-1]:,.2f}")
print(f"Middle band: ${sma_bb[-1]:,.2f}")
print(f"Lower band: ${lower_band[-1]:,.2f}")
print(f"Current price: ${current_price:,.2f}")

# Bollinger Bands signal
bb_position = (current_price - lower_band[-1]) / (upper_band[-1] - lower_band[-1])
print(f"Price position in Bollinger Bands: {bb_position:.2%}")

if bb_position > 0.8:
    bb_signal = "Near upper band, possible pullback"
elif bb_position < 0.2:
    bb_signal = "Near lower band, possible rebound"
else:
    bb_signal = "In middle of bands, trend to be observed"

print(f"Bollinger Bands signal: {bb_signal}")

# Generate candlestick data
candlesticks = []
for i in range(1, min(50, len(prices))):
    # Simulate candlestick data
    close_price = prices[i]
    open_price = prices[i-1]
    high_price = max(open_price, close_price) + random.uniform(0, abs(close_price - open_price) * 0.5)
    low_price = min(open_price, close_price) - random.uniform(0, abs(close_price - open_price) * 0.5)
    volume = random.uniform(100, 1000)

    candlestick = Candlestick(
        timestamp=time.time() + i * 3600,  # 1-hour interval
        open=open_price,
        high=high_price,
        low=low_price,
        close=close_price,
        volume=volume
    )
    candlesticks.append(candlestick)

# Support and resistance analysis
if len(candlesticks) >= 40:
    support_levels, resistance_levels = TechnicalAnalysis.support_resistance(candlesticks, 5)

    print(f"\nSupport and Resistance Analysis:")
    print(f"Number of support levels: {len(support_levels)}")
    print(f"Number of resistance levels: {len(resistance_levels)}")

    if support_levels:
        print(f"Nearest support level: ${max(support_levels):,.2f}")
    if resistance_levels:
        print(f"Nearest resistance level: ${min(resistance_levels):,.2f}")

# Candlestick pattern analysis
print(f"\nLatest Candlestick Pattern Analysis:")
latest_candle = candlesticks[-1]
print(f"Type: {'Bullish' if latest_candle.is_bullish else 'Bearish'}")
print(f"Body size: ${latest_candle.body_size:,.2f}")
print(f"Upper shadow: ${latest_candle.upper_shadow:,.2f}")
print(f"Lower shadow: ${latest_candle.lower_shadow:,.2f}")

if latest_candle.is_doji:
    print("Pattern: Doji - Market indecision")
elif latest_candle.upper_shadow > latest_candle.body_size * 2:
    print("Pattern: Shooting star/Inverted hammer - Possible top")
elif latest_candle.lower_shadow > latest_candle.body_size * 2:
    print("Pattern: Hammer - Possible bottom")
else:
    print("Pattern: Regular candlestick")

Chapter Summary

This chapter covered core knowledge of cryptocurrency trading:

  1. Exchange Mechanism:

    • Order matching engine principles
    • Buy and sell order book maintenance
    • Trade matching algorithms
    • Fee calculation
  2. Order Types:

    • Market Order: Immediate execution, price volatility risk
    • Limit Order: Specified price, possible partial fill
    • Stop Order: Risk control, automatic stop loss
    • Advanced Orders: Iceberg orders, trailing stops, etc.
  3. Trading Strategies:

    • DCA Strategy: Gradual position building, risk reduction
    • Grid Trading: Range-bound market arbitrage
    • Momentum Strategy: Trend following
    • Arbitrage Strategy: Cross-platform price difference profit
  4. Technical Analysis:

    • Moving Averages: Trend identification
    • RSI Indicator: Overbought/oversold determination
    • MACD Indicator: Momentum analysis
    • Bollinger Bands: Volatility analysis
    • Support/Resistance: Key price levels
  5. Risk Management:

    • Position control
    • Stop loss setting
    • Diversification
    • Emotional control

Mastering these trading fundamentals is an important prerequisite for cryptocurrency investment. In the next chapter, we will dive deep into DeFi and smart contract applications.