# 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)
# 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)
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)
# 市价单
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)
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)
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)
目录结构示例: