四个月从零搭建正期望值交易系统:规则、回测与资金管理全解析
2026/9/21 18:54:58 网站建设 项目流程

如果你最近开始尝试用规则约束自己的交易,或者已经写了一些简单的指标脚本,却仍然觉得“赚钱靠运气”,那这篇文章就是为你准备的。

交易中最难的地方,不是学会某个指标,也不是找到某个“必胜”的买卖点,而是回答一个更基础的问题:当你连续亏掉五笔之后,还敢不敢继续按原计划执行。如果答案是不敢,那么你手里那套方法再漂亮,也只是一个无法兑现的“预期”。

把交易逻辑写成规则,把规则变成代码或检查单,再用历史数据去验证,最后在真实行情中持续记录和复盘——这整条链路,才是“正期望值交易系统”真正要解决的工程问题。本文会以四个月周期为时间线,从概念、数据、回测、资金管理、复盘五个角度,把搭建过程中最容易被忽略的细节拆开讲清楚。

先给一个明确判断:正期望值交易系统的核心不是胜率,而是“风险可控前提下的赔率结构优势”。你需要做的不是看对大多数行情,而是让对的那些单子赚得比错的单子亏得多,同时保证自己在概率优势兑现之前,不会因为一次极端行情或一连串小额亏损而出局。

1. 为什么搭建系统需要以“四个月”为周期

很多人对交易系统有一个误解:以为有了一个入场信号,就算系统搭建完成。实际上,入场信号只是系统的最表层。一个真正完整的系统,至少要覆盖“什么条件下入场”“什么条件下出场”“错了亏多少”“对了赚多少”“当前舱位应该下多重”五个环节,其中任何一个环节缺失,系统都处于不可验证的状态。

四个月是一个比较合理的搭建周期,原因是它能覆盖一个相对完整的“规则定义—数据验证—小资金试运行—复盘修正”循环:

  • 第1个月:把交易思路规则化,建立交易日志,积累前期的行为数据。
  • 第2个月:写回测代码或手工回溯,验证规则在历史行情中的期望值表现。
  • 第3个月:用小资金或模拟盘开始跟随执行,记录实时决策与情绪偏差。
  • 第4个月:集中复盘执行数据,区分“系统问题”和“执行问题”。

这套节奏的核心目的不是快速盈利,而是尽快进入“可迭代”的状态。四个月后,你会得到一组自己的数据:每一笔交易按什么理由入场、实际走成了什么样、哪些规则在执行中最容易被破坏。这些数据比任何高深理论都有价值。

所以,四个月搭建交易系统的本质,是把一个模糊的想法变成一个有统计依据、有执行边界、能够持续改进的闭环。这个闭环一旦建立,后面所有优化才有意义。

2. 正期望值交易系统的核心概念

2.1 期望值到底是什么

“正期望值”听起来像个数学术语,但它可以还原成一句很直白的话:当你按同一套规则重复交易足够多次之后,扣除成本,平均每笔交易是赚钱的。

它的计算公式并不复杂:

期望值 EV = 胜率 × 平均单笔盈利 − 败率 × 平均单笔亏损

举一个最简单的例子。假设你的账户中单笔风险金额为 3000 元,也就是每笔最多亏 3000 元。系统过去数据显示胜率是 40%,平均盈利单为 6000 元,平均亏损单为 3000 元:

EV = 0.4 × 6000 − 0.6 × 3000 = 2400 − 1800 = 600

这意味着在理想统计条件下,每一笔交易的平均期望收益为 600 元。注意,这并不代表下一笔一定会赚 600 元,它只代表长期重复之后,概率优势会逐步体现出来。

2.2 胜率与盈亏比的关系

很多新手会把“胜率”当成系统的第一指标,这是一种常见偏差。高胜率系统不一定赚钱,低胜率系统也不一定亏钱,关键在于胜率和盈亏比的组合。

系统类型胜率平均盈亏比期望值方向
高胜率低盈亏比65%0.5:1可能为负
低胜率高盈亏比35%2.5:1可能为正
均衡型45%1.6:1视成本决定

为什么高胜率系统反而可能亏钱?因为如果每次赚钱只赚小钱,每次亏钱却亏大钱,那么 65% 的胜率也扛不住少数几笔大亏损。反过来,止损即时、盈利留得住,才是低胜率系统能长期生存的原因。

2.3 正期望值的前提:风险边界

一个经常被忽略的事实是:期望值公式里的平均亏损,必须建立在“每笔风险固定”的基础上。如果止损不执行,平均亏损会被拉得很大,期望值会瞬间转负。

所以正期望值系统的完整表述,应该是“在风险可控的前提下,长期期望值为正”。这个“风险可控”体现在三个层面:

  1. 每笔交易的最大亏损金额提前确定。
  2. 止损逻辑可自动化执行,不依赖临场感觉。
  3. 单笔风险占总资金比例固定,避免亏损后报复性加仓。

清楚了这一点,再去看各类交易策略,你就能快速判断它们是否具备系统化的基础:如果一笔交易没有事先定义止损,那么无论入场信号看起来多么合理,它都还不是一个完整的系统逻辑。

3. 构建系统前必须先做规则化和日志化

3.1 为什么交易记录比技术指标更重要

搭建系统最忌讳的一步,是一开始就想着写一个复杂的回测框架。事实上,绝大多数普通交易者积累的有效数据太少,甚至没有统一的记录口径,这种情况下回测再精确,也只是基于一堆不可靠数据的机械计算。

以交易日志为起点,有另外一个现实原因:它能同时记录“系统行为”和“人的行为”。比如系统规则说今天应该等待信号,但你实际提前入场了;系统规则说跌破支撑位止损,但你因为“觉得会反弹”而没有执行。这些偏差不会被历史行情数据记录,只有交易日志能暴露它们。

3.2 交易日志字段建议

一份能用于系统分析的交易日志,至少应该包含以下字段:

字段说明
交易日期时间用于分析时段特征,避免仅凭记忆复盘
品种/标的区分不同市场、不同波动特征的品种
入场理由对应哪一条预设规则,便于统计规则有效性
入场价格/时间计算滑点和执行偏差
止损价格预设的最大风险金额
止盈价格或出场规则明确是固定出场、移动出场还是信号出场
仓位大小便于计算实际盈亏与回撤
事后盈亏截至出场的实际盈亏金额
执行偏差说明是否完全按规则执行,如果没有,原因是什么

这里需要特别强调“入场理由”字段。它让复盘可以按规则维度做聚合统计:如果你的十条规则里其实只有一条在稳定获利,那么系统优化的方向就非常清晰了,而不是把精力平均分配到所有信号上。

3.3 日志数据如何辅助期望值度量

积累到 30 到 50 笔交易之后,就可以按规则维度做初步统计:

从交易日志中过滤出规则A触发过的所有交易 统计规则A的胜率、平均盈利、平均亏损 计算规则A的期望值 对比规则B、规则C 的期望值

这个过程的意义在于:你不再问“今天赚没赚钱”,而是问“哪套规则在长期统计上更有优势”。前者是情绪波动,后者才是系统迭代的方向。四个月周期中,前一个月重点做规则化和日志化,数据量越多,后续回测越有参考意义。

4. 环境准备与最小回测代码实现

4.1 硬件与软件准备

搭建交易系统并不需要昂贵的服务器,一台普通的开发笔记本就能完成从数据处理到回测验证的整个流程。以下环境可以作为参考,具体版本请以你本地的实际环境为准:

  • 操作系统:Windows / macOS / Linux 均可。
  • Python 3.9 或更高版本,建议使用 Anaconda 或 venv 管理依赖。
  • 依赖库:pandas、numpy、matplotlib,用于数据处理、统计计算和可视化。
  • 开发工具:VS Code、PyCharm,或直接使用 Jupyter Notebook。
  • 数据来源:国内期货/股票/数字货币等品种的历史 K 线数据,需要提前整理成 CSV 文件。

建议在开始写回测代码前,先把历史数据统一成 CSV 格式,至少包含“时间、开盘价、最高价、最低价、收盘价、成交量”六列。数据质量决定回测结果的可信度,这一步不能省。

4.2 示例1:用 Python 计算交易期望值

假设你已经通过交易日志导出一份交易记录,包含每笔交易的盈亏金额,下面的代码可以直接计算这套规则的胜率、盈亏比和期望值:

# expectancy.py import pandas as pd def calculate_expectancy(trades: pd.DataFrame, risk_per_trade: float = 0.01) -> dict: """ 根据交易记录计算期望值相关指标。 参数: trades: 必须包含 pnl 字段,表示每笔交易的盈亏金额。 risk_per_trade: 单笔风险占总资金比例,默认 1%,仅用于参考字段。 返回: 包含胜率、平均盈利、平均亏损、盈亏比、期望值的字典。 """ assert 'pnl' in trades.columns, "交易记录必须包含 pnl 字段" trades = trades.dropna(subset=['pnl']) total = len(trades) if total == 0: raise ValueError("交易记录为空,无法计算期望值") win_trades = trades[trades['pnl'] > 0] loss_trades = trades[trades['pnl'] <= 0] win_rate = len(win_trades) / total avg_win = win_trades['pnl'].mean() if len(win_trades) > 0 else 0.0 avg_loss = abs(loss_trades['pnl'].mean()) if len(loss_trades) > 0 else 0.0 profit_loss_ratio = avg_win / avg_loss if avg_loss > 0 else float('inf') expectancy = win_rate * avg_win - (1 - win_rate) * avg_loss return { 'total_trades': total, 'win_rate': win_rate, 'avg_win': avg_win, 'avg_loss': avg_loss, 'profit_loss_ratio': profit_loss_ratio, 'expectancy': expectancy } if __name__ == '__main__': # 示例数据,仅用于演示,请替换为真实交易日志 demo_data = { 'pnl': [1200, -800, 600, 1500, -1000, 900, -500, -700, 2000, 300] } df = pd.DataFrame(demo_data) result = calculate_expectancy(df) for key, value in result.items(): print(f"{key}: {value:.2f}" if isinstance(value, float) else f"{key}: {value}")

运行这段代码,会在终端看到以下输出:

total_trades: 10 win_rate: 0.70 avg_win: 1083.33 avg_loss: 750.00 profit_loss_ratio: 1.44 expectancy: 533.33

这组示例数据显示期望值为正,但样本量只有 10 笔,统计意义并不强。实际使用时应至少积累 30 到 50 笔以上,同时分规则分别统计,避免把不同规则的交易混在一起。

4.3 示例2:一个简单的均线策略回测骨架

下面是教学用的简化回测代码,用于演示一条完整的策略验证链路:计算快慢均线、生成信号、按信号计算策略收益。

# backtest_sma.py import pandas as pd import numpy as np def run_sma_backtest( df: pd.DataFrame, fast: int = 5, slow: int = 20, fee_rate: float = 0.0005 ) -> pd.DataFrame: """ 双均线策略回测骨架。 策略逻辑: 快线上穿慢线时产生买入信号,下穿时产生卖出信号。 次日开盘按信号执行,考虑单边手续费。 参数: df: 必须包含 close 列。 fast: 快线周期。 slow: 慢线周期。 fee_rate: 单边手续费率,0.0005 表示万分之五。 返回: 带信号、持仓和策略收益字段的 DataFrame。 """ data = df.copy() data['sma_fast'] = data['close'].rolling(window=fast).mean() data['sma_slow'] = data['close'].rolling(window=slow).mean() data['signal'] = np.where(data['sma_fast'] > data['sma_slow'], 1, 0) data['position'] = data['signal'].shift(1) data['ret'] = data['close'].pct_change() data['strategy_ret'] = data['position'] * data['ret'] # 在持仓变化时扣除手续费 data['trade_flag'] = data['position'].diff().abs().fillna(0) data['strategy_ret'] = data['strategy_ret'] - data['trade_flag'] * fee_rate data['cum_ret'] = (1 + data['strategy_ret']).cumprod() return data # 示例用法,请将文件替换为自己的数据 if __name__ == '__main__': df = pd.read_csv('daily_kline.csv', parse_dates=['time']) result = run_sma_backtest(df, fast=5, slow=20) print(result[['time', 'close', 'sma_fast', 'sma_slow', 'position', 'cum_ret']].tail(10))

这份代码做对了几件关键的事:

  1. signal.shift(1)避免“用当日收盘信号做当日交易”的未来函数。
  2. position.diff()识别换手时点并扣除手续费。
  3. 通过累计收益cum_ret直观观察策略净值曲线。

但要注意,这只是教学骨架,它没有考虑涨跌停无法成交、盘中滑点、初始资金约束等问题。回测结果必须结合真实市场约束做二次校验。

4.4 示例3:基于固定风险的仓位计算

仓位管理决定了系统在遭遇连续亏损时能否存活。下面的函数按“固定风险比例”计算应该投入的仓位:

# position_size.py def position_size( account_equity: float, risk_pct: float = 0.01, stop_loss_pct: float = 0.05 ) -> float: """ 根据固定风险比例计算建议仓位。 公式: 单笔风险金额 = 账户资金 × 风险百分比 建议仓位 = 单笔风险金额 / 止损比例 参数: account_equity: 当前账户总资金。 risk_pct: 单笔风险占总资金比例,0.01 表示 1%。 stop_loss_pct: 止损距离占账面总仓位的比例,0.05 表示 5%。 返回: 建议的仓位金额。 """ risk_amount = account_equity * risk_pct size = risk_amount / stop_loss_pct return size if __name__ == '__main__': # 示例:账户 10 万元,单笔风险 1%,止损 5% print("建议仓位:", round(position_size(100000, 0.01, 0.05), 2))

运行结果:

建议仓位: 20000.0

这个逻辑的核心目的是:当连续亏损发生时,每一笔风险金额都被限制在账户的固定比例内,保住本金,等待概率优势回归。

5. 资金管理与回撤控制

5.1 为什么正期望系统也会爆仓

一个看上去“胜率不错、期望值为正”的系统,在实盘中依然可能失败,最常见的原因是资金管理失控。最典型的情形是:连续亏损几次后,交易者为了快速回本,把单笔风险从 1% 突然提高到 10%。本金回撤速度瞬间放大,一旦运气不好,一次极端行情就能让账户接近清零。

这正是“正期望值”和“能让你赚钱”之间最大的鸿沟:前者描述的是概率统计,后者要求你在不利阶段活下来。

5.2 最大回撤与连续亏损

复盘时必须计算的指标是最大回撤,也就是资金曲线从最高点回落的最大幅度。用 Python 计算最大回撤的代码如下:

# drawdown.py import pandas as pd import numpy as np def max_drawdown(equity_curve: pd.Series) -> float: """ 计算最大回撤。 参数: equity_curve: 账户净值序列。 返回: 最大回撤比例,例如 -0.18 表示回撤 18%。 """ peak = equity_curve.cummax() drawdown = (equity_curve - peak) / peak return drawdown.min() # 示例 equity = pd.Series([100000, 102000, 101000, 98000, 97000, 103000]) print("最大回撤:", max_drawdown(equity))

输出:

最大回撤: -0.05

这一步看似简单,却是复盘时判断系统是否处于“危险状态”的关键依据。单次亏损可控,不代表回撤可控;回撤可控,才意味着未来还有重新盈利的资本。

5.3 资金管理基本原则

  • 每笔风险固定:单笔亏损不超过总资金的 1% 到 2%,数据回测环境好的系统可以尝试 2%,否则用 1% 更稳妥。
  • 连亏后依然按规则执行:不建议因为连续亏损而随意缩小仓位,规则如果不是在改进版本,就不应该凭空改变。
  • 回撤达到阈值时降档:例如账户回撤超过 10% 之后,将风险参数自动下调一半,直到净值创新高再恢复。
  • 避免重仓单一标的:即使系统期望为正,单品种的极端行情也会破坏统计样本的稳定性。

资金管理不是一个“可选项”,而是交易系统当中的一个独立模块,和入场信号、出场规则处于同等地位。没有资金管理的系统,严格来说不具备被实盘验证的资格。

6. 复盘方法论:从数据中发现系统问题

6.1 复盘的四个维度

四个月周期的最后一个阶段,核心任务是复盘。复盘不能只盯着“赚了还是亏了”,而要从四个维度去拆:

指标计算方式反映的系统问题
胜率盈利笔数 / 总笔数入场规则与市场状态是否匹配
盈亏比平均盈利 / 平均亏损出场规则与止损设置是否合理
期望值胜率×平均盈利 − 败率×平均亏损系统整体是否具有统计优势
最大回撤净值曲线峰值到谷底的回撤幅度仓位与风险控制是否匹配

比如胜率很高但盈亏比偏低,说明赚钱时拿不住,出场逻辑需要调整;盈亏比很高但胜率过低,说明入场时机太早或太窄,需要优化入场条件。

6.2 用规则维度聚合分析

如果交易日志有记录“入场理由”字段,可以用 pandas 分规则做聚合统计:

# review_by_rule.py import pandas as pd def review_by_rule(trades: pd.DataFrame) -> pd.DataFrame: """ 按入场规则聚合统计交易表现。 """ grouped = trades.groupby('entry_reason')['pnl'].agg( total_trades='count', avg_pnl='mean', win_rate=lambda x: (x > 0).mean() ).reset_index() grouped['profit_loss_ratio'] = grouped.apply( lambda r: trades[(trades['entry_reason'] == r['entry_reason']) & (trades['pnl'] > 0)]['pnl'].mean() / max(abs(trades[(trades['entry_reason'] == r['entry_reason']) & (trades['pnl'] <= 0)]['pnl'].mean()), 1e-9), axis=1 ) return grouped if __name__ == '__main__': demo = pd.DataFrame({ 'entry_reason': ['R1_breakout', 'R2_pullback', 'R1_breakout', 'R3_reversal', 'R2_pullback'], 'pnl': [1200, -800, 1800, -300, 600] }) print(review_by_rule(demo))

拿到这份聚合表之后,真正的判断就开始了:如果规则 R1 贡献了主要盈利,而规则 R3 期望值为负,最务实的优化策略是先把负期望规则停掉,而不是继续往系统里堆更多新指标。

6.3 区分“系统问题”与“执行问题”

复盘时还有一个很容易踩的坑:把执行问题当成系统问题,然后去修改规则。比如交易者因为犹豫,漏掉了一笔应该执行的盈利单;此时如果把系统的入场条件改得更灵敏,反而会破坏原有统计结构。

正确的做法是:交易日志里的“执行偏差说明”字段专门记录这种情况,复盘时先看哪些单子没有按规则执行,再看哪些单子按规则执行但亏了,最后才决定要不要改规则本身。这是一个“先纪律后优化”的流程。

7. 常见问题与排查思路

下面这张表总结了搭建交易系统和实盘试运行阶段最常遇到的问题,可以直接作为排查索引。

问题现象可能原因排查方式解决方案
回测收益很高,实盘却持续亏损回测存在未来函数,或未扣除手续费滑点检查信号是否用到当日收盘价、是否计入交易成本用次日开盘或次日收盘确认信号,加入手续费与滑点
信号频繁触发,但总盈亏很小均线类规则在震荡行情中不断止损统计震荡行情占比,查看单笔盈亏比加入趋势过滤条件,或延长快线周期
连续亏损后心态崩盘,手动干预仓位过重,超过心理承受能力检查单笔风险比例和账户回撤降低单笔风险比例到 1% 以内,严格执行固定风险
止损经常被扫掉后又继续涨止损距离太近,或入场时机太晚统计止损单被扫后的后续走势扩大止损距离,或等待更合理的入场点
交易记录混乱,无法统计期望值没有统一日志模板,字段缺失检查是否记录入场理由、止损价、实际盈亏强制使用统一交易日志模板,自动化记录
同一套参数在不同品种上表现差异极大过拟合单一品种,或品种波动特征不同分品种统计参数稳定性按品种分别回测,避免用一组参数通吃
新加入一个过滤条件后系统反而变差过拟合历史行情,自由度过高对比添加前后的样本外数据表现用样本外数据做验证,避免频繁增加参数

在实盘试运行的前几个月,新手最容易犯的错误是同时调整多个变量:既改入场,又改出场,还改仓位。每次只改一个模块,记录修改前后的统计指标,是避免系统失控的基本原则。

8. 搭建交易系统的最佳实践清单

结合四个月周期的实战复盘,我总结了下面这份“从零搭建交易系统”的检查清单。它不是万能的,但足以帮你避开大多数早期陷阱。

  1. 规则化优先:先花一周时间用文字写清入场条件、出场条件、止损位置、仓位大小,没有写到纸上的规则,都是不存在的规则。
  2. 日志先行:在写任何回测代码之前,先启动交易日志记录。日志字段保持稳定,后续才能做规则聚合分析。
  3. 回测去未来函数:用信号形成后的下一个可执行价格成交,扣除手续费和合理滑点,样本外数据单独留出。
  4. 先验证样本外表现:不要用同一段历史数据反复调参,至少保留最近一段行情不参与参数优化。
  5. 固定单笔风险:从 1% 开始,稳定后再根据回撤数据微调。不要因为连亏而随意放大风险。
  6. 先复盘执行,再修改规则:交易日志中的执行偏差,永远优先于系统逻辑问题。
  7. 隔离情绪:把系统的“决策输出”和“情绪体验”分开。当你能把系统中某一笔交易的得失看淡,把焦点放在长期期望值上时,系统才真正具有可执行性。

这套清单的核心思想,是把交易系统的搭建当成一次软件工程实践:先定义需求,再写最小实现,再做测试验证,最后持续迭代。这个过程中,最关键的变量不是行情,而是你自己的纪律性和反馈能力。

9. 总结与后续学习方向

用四个月的时间搭建交易系统,其实是一个“祛魅”的过程。你会发现,真正决定系统长期表现的,并不是某个神奇的指标,而是一系列朴素工程的叠加:清晰的规则、可靠的日志、诚实的回测、固定的风险参数、以及持续不断的复盘修正。

如果现阶段你的交易记录还停留在“大概赚了”“大概亏了”,下一件事就非常明确:先把日志表建起来。当你有了第一批不含执行偏差的数据,再回过头来看本篇文章中的期望值计算、回测骨架和仓位公式,你会有完全不一样的体会。

后续可以继续深入的方向包括:参数稳定性分析和稳健性检验、多品种横向对比、基于机器学习的因子筛选、实盘交易自动化与监控告警。每一步都值得单独研究和实践,但有前提:你的基础系统闭环必须已经稳定运转,否则更多技术只会增加噪声。

最后想提醒一点:交易系统是概率游戏,没有人能保证某个系统一定盈利。本文所有代码与思路仅用于技术交流和方法参考,不构成任何投资建议。如果你正在搭建自己的系统,建议从小资金、模拟盘开始,先把流程跑通,再逐步扩大验证范围。对一个普通开发者来说,控制风险的能力,比追求盈利的速度更重要。

如果你也在实践交易系统的搭建与复盘,欢迎在评论区或讨论组分享你的问题和经验。系统化交易这条路上,好的反馈循环本身,就是最有价值的成长资源。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询