Day 1 — CCXT 基本下单 + paper_trade.py 框架

# paper_trade.py

import pandas as pd
from datetime import datetime

class PaperExchange:
    """模拟交易所下单"""
    def __init__(self, balance=10000):
        self.balance = balance
        self.positions = {}  # symbol -> qty
        self.order_log = []

    def fetch_balance(self):
        return self.balance

    def create_order(self, symbol, side, qty, price=None, type='market'):
        order = {
            "symbol": symbol,
            "side": side,
            "qty": qty,
            "price": price,
            "type": type,
            "status": "filled",
            "time": datetime.now()
        }

        # 简单市场成交逻辑
        if side.lower() == "buy":
            cost = price * qty if price else qty * 1  # 简化
            if cost > self.balance:
                order['status'] = "rejected"
            else:
                self.balance -= cost
                self.positions[symbol] = self.positions.get(symbol, 0) + qty
        elif side.lower() == "sell":
            self.positions[symbol] = self.positions.get(symbol, 0) - qty
            self.balance += price * qty if price else qty * 1

        self.order_log.append(order)
        return order

# Demo
exchange = PaperExchange()
print(exchange.fetch_balance())
order = exchange.create_order("BTC/USDT", "buy", 0.1, price=50000)
print(order)


Day 2 — 策略下单接口

# order_manager.py
class OrderManager:
    def __init__(self, exchange):
        self.exchange = exchange

    def place_order(self, symbol, side, qty, price=None, type='market'):
        order = self.exchange.create_order(symbol, side, qty, price, type)
        print(f"Placed order: {order}")
        return order

# Demo
om = OrderManager(exchange)
om.place_order("BTC/USDT", "buy", 0.05, price=50000)


Day 3 — 仓位管理风控

class RiskManager:
    def __init__(self, max_risk_pct=0.02, max_position=0.2):
        self.max_risk_pct = max_risk_pct
        self.max_position = max_position  # 相对账户

    def check_order(self, exchange, symbol, qty, price):
        balance = exchange.fetch_balance()
        position_value = exchange.positions.get(symbol, 0) * price
        risk = qty * price / balance

        if risk > self.max_risk_pct:
            print("Order rejected: exceeds max risk per trade")
            return False
        if (position_value + qty * price)/balance > self.max_position:
            print("Order rejected: exceeds max position")
            return False
        return True

# Demo
rm = RiskManager()
if rm.check_order(exchange, "BTC/USDT", 0.1, 50000):
    om.place_order("BTC/USDT", "buy", 0.1, 50000)


Day 4 — 限价单 / 市价单 / OCO 模拟

# 市价单
om.place_order("BTC/USDT", "buy", 0.05, type='market')

# 限价单(模拟:仅记录,不成交直到条件满足)
def place_limit_order(exchange, symbol, side, qty, price):
    return {"symbol": symbol, "side": side, "qty": qty, "price": price, "type":"limit", "status":"open"}

limit_order = place_limit_order(exchange, "BTC/USDT", "buy", 0.05, 49000)
print(limit_order)

# OCO (One Cancels Other) 简单模拟
oco_orders = [
    place_limit_order(exchange, "BTC/USDT", "sell", 0.05, 51000),
    place_limit_order(exchange, "BTC/USDT", "sell", 0.05, 48000)
]
print("OCO orders:", oco_orders)


Day 5 — 日志系统 + 简单 alert

import logging
from logging.handlers import RotatingFileHandler

# 日志设置
handler = RotatingFileHandler("logs/paper_trade.log", maxBytes=2_000_000, backupCount=3)
logging.basicConfig(handlers=[handler], level=logging.INFO, format='%(asctime)s %(levelname)s %(message)s')

def log_order(order):
    logging.info(f"Order: {order}")
    if order['status'] == 'rejected':
        logging.error("Order rejected!")

# Demo
order = om.place_order("BTC/USDT", "buy", 0.1, 50000)
log_order(order)


Day 6 — 回撤/恢复逻辑(state persistence)

import json
import os

STATE_FILE = "bot_state.json"

def save_state(exchange):
    state = {
        "balance": exchange.balance,
        "positions": exchange.positions,
        "orders": exchange.order_log
    }
    with open(STATE_FILE, "w") as f:
        json.dump(state, f, default=str)
    print("State saved.")

def load_state(exchange):
    if os.path.exists(STATE_FILE):
        with open(STATE_FILE, "r") as f:
            state = json.load(f)
            exchange.balance = state['balance']
            exchange.positions = state['positions']
            exchange.order_log = state['orders']
        print("State restored.")

# Demo
save_state(exchange)
load_state(exchange)


Day 7 — 复盘 / 打包 bot

目录结构示例: