第3章:Python基础速通

做市系统说到底就是一堆数字游戏。你想想看,买卖价差、库存管理、订单路由,哪个离得开代码?Python 是我最常用的工具,没有之一。这一章咱们就把基础打牢,后面写策略才不会卡壳。

3.1 变量与数据类型

Python 的变量不需要声明类型。你直接赋值就行。我个人习惯用下划线命名法,比如 bid_priceask_volume,这样一眼就能看出含义。

# 做市系统里最常见的变量
bid_price = 100.50      # 浮点数,买一价
ask_price = 100.55      # 浮点数,卖一价
spread = ask_price - bid_price  # 价差
symbol = "BTC-USDT"     # 字符串,交易对
is_active = True        # 布尔值,策略是否运行
order_count = 0         # 整数,订单数量
我的经验:做市系统里浮点数精度是个坑。比如计算价差时,0.05 和 0.0500000001 可能差出一个滑点。我建议用 Decimal 处理价格,别用 float。

Python 的数据类型主要就这几种:

类型 例子 说明
int 100, -5, 0 整数,订单数量、计数器
float 100.50, 0.001 浮点数,价格、数量
str "ETH", "buy" 字符串,交易对、订单类型
bool True, False 布尔值,开关、状态判断

嗯,这里要注意:Python 是动态类型,但别滥用。我在项目中见过有人把变量名 price 一会儿当字符串用,一会儿当浮点数用,最后 debug 到崩溃。保持类型一致,这是好习惯。

3.2 列表与字典

做市系统里,列表和字典是绝对的主力。列表存订单簿的档位,字典存订单的详细信息。

# 列表:存储订单簿的卖五档
ask_levels = [100.55, 100.60, 100.65, 100.70, 100.75]
# 列表操作
ask_levels.append(100.80)   # 加一档
ask_levels.pop(0)           # 移除第一档
best_ask = ask_levels[0]    # 取最优卖价

# 字典:存储一个订单的全部信息
order = {
    "order_id": "12345",
    "symbol": "BTC-USDT",
    "side": "buy",
    "price": 100.50,
    "quantity": 1.0,
    "status": "filled"
}
# 字典操作
order["status"] = "cancelled"   # 修改状态
order["filled_qty"] = 0.5       # 新增字段
del order["quantity"]           # 删除字段
避坑指南:我曾经在回测系统里用列表存了 10 万条 tick 数据,然后循环里频繁用 insert(0, ...) 插入数据。结果回测跑了 3 个小时没跑完。后来改成 deque,10 分钟搞定。列表头部插入是 O(n),别踩这个坑。

列表和字典的嵌套也很常见。比如订单簿就是一个列表套字典的结构:

orderbook = {
    "bids": [{"price": 100.50, "size": 1.5}, {"price": 100.45, "size": 2.0}],
    "asks": [{"price": 100.55, "size": 1.0}, {"price": 100.60, "size": 3.0}]
}

3.3 函数定义

函数是代码复用的基础。做市策略里,计算价差、检查库存、发送订单,这些都应该写成函数。

def calculate_spread(bid_price, ask_price):
    """计算买卖价差"""
    return ask_price - bid_price

def check_inventory(current_qty, max_qty):
    """检查库存是否超限"""
    if abs(current_qty) > max_qty:
        return False  # 需要调整
    return True

# 带默认参数的函数
def send_order(symbol, side, price, quantity, order_type="limit"):
    """发送订单到交易所"""
    # 实际代码会调用交易所 API
    print(f"发送{order_type}订单: {side} {quantity} {symbol} @ {price}")
    return {"order_id": "new_order_001"}
我的习惯:每个函数都写 docstring。别嫌麻烦。我去年重构一个老策略时,看到自己 3 年前写的函数没注释,愣是看了半小时才看懂。写清楚输入输出,后面的人(包括你自己)会感谢你的。

函数返回值可以多个:

def get_market_data(symbol):
    """获取市场数据,返回最新价和24小时涨跌幅"""
    last_price = 100.50
    change_24h = 2.5
    return last_price, change_24h

price, change = get_market_data("BTC-USDT")

3.4 面向对象编程入门

做市系统天然适合用面向对象来设计。一个策略是一个对象,一个订单管理器是一个对象,一个风险控制器也是一个对象。说白了,就是把数据和操作数据的方法打包在一起。

class MarketMaker:
    """做市商策略类"""
    
    def __init__(self, symbol, spread_target):
        self.symbol = symbol
        self.spread_target = spread_target
        self.position = 0
        self.orders = []
    
    def update_position(self, qty):
        """更新持仓"""
        self.position += qty
        print(f"当前持仓: {self.position}")
    
    def place_orders(self, bid_price, ask_price):
        """挂出买卖订单"""
        # 实际代码会调用交易所 API
        self.orders.append({"side": "buy", "price": bid_price})
        self.orders.append({"side": "sell", "price": ask_price})
        print(f"已挂单: 买@{bid_price} 卖@{ask_price}")
    
    def check_risk(self):
        """风险检查"""
        if abs(self.position) > 10:
            print("⚠️ 持仓超限,需要平仓")
            return False
        return True

# 使用这个类
mm = MarketMaker("BTC-USDT", 0.05)
mm.place_orders(100.50, 100.55)
mm.update_position(1.5)
mm.check_risk()

核心思路:类把状态和行为封装在一起。做市策略的状态包括持仓、订单列表、价差目标;行为包括挂单、撤单、风险检查。用类来组织代码,比散落一地的函数清晰得多。

继承也很有用。比如你可以写一个基础策略类,然后不同的币种策略继承它:

class BaseStrategy:
    def __init__(self, symbol):
        self.symbol = symbol
    
    def calculate_spread(self):
        raise NotImplementedError("子类必须实现此方法")

class BTCMarketMaker(BaseStrategy):
    def calculate_spread(self):
        # BTC 的价差计算逻辑
        return 0.05

class ETHMarketMaker(BaseStrategy):
    def calculate_spread(self):
        # ETH 的价差计算逻辑
        return 0.03

3.5 异常处理

做市系统最怕什么?程序突然崩溃。网络断了、交易所返回错误、数据格式不对,这些在实盘中天天发生。没有异常处理,你的策略可能亏到爆仓才停下来。

def place_order_safe(symbol, side, price, quantity):
    """带异常处理的挂单函数"""
    try:
        # 模拟发送订单
        result = send_order(symbol, side, price, quantity)
        return result
    except ConnectionError:
        print("网络连接失败,重试中...")
        # 重试逻辑
        return None
    except ValueError as e:
        print(f"参数错误: {e}")
        # 记录日志,通知运维
        return None
    except Exception as e:
        print(f"未知错误: {e}")
        # 兜底处理,至少保证程序不崩溃
        return None
    finally:
        print("订单处理完成")
避坑指南:我曾经在实盘策略里忘了加异常处理,结果交易所返回了一个空数据,程序直接崩溃。等我发现时,策略已经停了 15 分钟,错过了好几波行情。从那以后,所有可能出错的地方我都加了 try-except。

自定义异常也很有用:

class RiskLimitExceeded(Exception):
    """风险限额超限异常"""
    pass

def check_position_limit(position, limit=10):
    if abs(position) > limit:
        raise RiskLimitExceeded(f"持仓 {position} 超过限额 {limit}")
    return True

# 使用
try:
    check_position_limit(15)
except RiskLimitExceeded as e:
    print(f"⚠️ {e},执行平仓操作")
我的建议:异常处理不是越多越好。关键路径(网络请求、数据解析、订单操作)必须加。普通计算逻辑可以不加,否则代码里全是 try-except,反而影响可读性。把握好度。

本章知识体系

下面这张图把本章的核心知识点串起来了。你可以看到,变量和数据类型是基础,列表和字典是数据容器,函数是逻辑单元,面向对象是组织方式,异常处理是安全保障。五者缺一不可。

Python 基础速通 · 做市系统必备 变量与数据类型 int / float / str / bool 列表与字典 订单簿 / 订单信息 函数定义 复用 / 参数 / 返回值 面向对象编程 类 / 对象 / 继承 异常处理 try / except / finally 基础 → 容器 → 逻辑 → 组织 → 安全 五步构建做市系统的 Python 基石

这一章的内容就这些。变量和数据类型是砖瓦,列表和字典是框架,函数是工具,面向对象是蓝图,异常处理是安全网。把这些基础打牢,后面写策略的时候你会觉得特别顺手。


专注资料整理