拓冰建站拓冰建站
首页 / 资讯中心 / 正文

多数时间空仓:用代码纪律过滤无效交易

“90%散户输在管不住手”这句话在投资社区里流传了很久。比例未必经得起统计学检验但它确实点破了一个普遍问题很多人的亏损不是因为看不懂行情而是因为操作频率太高、太随意、太容易被盘面波动牵着走。今天这篇文章不讨论某只标的也不推荐任何指标组合而是想沿着一个更接近工程实践的思路展开——怎么通过一套明确规则甚至一段代码让策略在大多数时间保持空仓只在条件收敛时出手。我核心想表达一个判断这类“多数时间空仓”的策略真正的价值不是抓住更多机会而是主动过滤掉大量低质量机会。把“等待”作为策略的一等公民而不是当作“没做事”是它和普通短线打法之间最本质的区别。下面从问题本质、策略设计、代码实现、回测验证和工程化落地五个层面拆开讲。1. 先看清楚高频操作到底在消耗什么1.1 交易成本不是“小事”很多人评估交易策略时注意力都放在“买对了没卖对”却很少认真算一笔账每多一次操作就要多承担一次手续费、点差或滑点以及可能的冲击成本。对散户来说单笔看起来不多但交易频率一旦上去这些成本不是线性累加而是在复利链条里持续拖后腿。举个例子一个策略如果一年交易 200 次假设单次综合成本千分之一那么一年 200 次交易意味着总成本可能达到本金的 20% 左右。这意味着策略在扣除成本之前必须赚到超过 20%实际才不亏。换句话说高频交易像一个隐形的吸水层把策略的含水量挤干以后剩下的才是真实收益。在程序化交易研究里我一般会把交易成本当作“策略设计的一部分”而不是事后才考虑的因素。如果回测时忽略成本实盘的结果会和回测差很多。止损、手续费、滑点、数据延迟这些都是真实世界的摩擦力。高频操作等于把这些摩擦力反复放大。1.2 情绪驱动才是最大的“隐性亏损”另一个更隐蔽的消耗是情绪驱动的决策链看到涨了想追看到跌了心慌亏了想马上扳回赚了一点又想落袋为安。这种“盘面刺激—情绪反应—立即下单”的闭环是大量无效交易的来源。频繁盯盘还会带来决策疲劳。一个人每天在几分钟内做几十次判断判断质量必然下降。表面看是“操作不够果断”实际上是给大脑塞了太多短期噪声让它失去了对中期趋势的判断力。更麻烦的是情绪会形成路径依赖一旦体验过“手痒然后立刻成交”的刺激感空仓反而变成一种难以忍受的状态。所以遇到“90%散户输在管不住手”这种说法时我更愿意把它理解为问题不是能力不足而是决策环境太容易触发非理性操作。要解决这个问题光靠“让自己忍住”是不靠谱的更好的方式是改变决策环境——用规则和程序把“忍不住的手”关掉。1.3 “等待”不是消极而是主动过滤很多人一听到“空仓等待”第一反应是错失机会。但从策略角度看机会不是每秒都存在。市场大部分时间处于震荡、无趋势或噪声主导的状态。这时强行交易就像在布满碎石的路上不断换车道不仅增加摩擦成本还容易撞上随机波动。如果把“空仓”设计成策略的默认状态信号未触发就不入场那么每次入场都意味着你的策略系统给出了一次较强的“同意”信号。这种主动过滤会把交易频率降下来也会让每一次出手有更明确的逻辑支撑。空仓不是在“等机会”而是在主动拒绝不满足条件的走势。2. 设计一个多数时间空仓的策略框架2.1 先建立四层过滤模型要做一个“80%时间空仓”的策略核心不是找一个神奇指标而是建立一套足够严格的过滤模型。我常用的思路是四层结构只有四层全部通过才开仓市场环境过滤判断当前市场是否处于适合交易的阶段。常见方式包括长期均线方向、指数均线、市场宽度等。环境不对直接不做。趋势方向过滤在环境允许的前提下确认当前标的方向。例如短期均线在长期均线上方或价格突破关键位置。波动率条件确认波动足够收敛或放大到适合启动。例如 ATR 低于或高于某个阈值代表行情要么在积蓄要么已经启动。风控前置入场前先算好最大亏损额度仓位大小由“单笔亏损上限 ÷ 止损距离”决定而不是由“想赚多少”决定。这四个条件任意一个不满足默认保持空仓。这也是策略能长期空仓的根本原因不是“没信号”而是多数时间里至少有一层过滤条件不成立。2.2 一个便于理解的信号示例技术指标只是工具重点是逻辑。我可以给一个比较保守的示例组合双均线方向作为趋势判断短期均线在长期均线上方视为趋势倾向偏多。ATR 相对放大作为波动启动条件当 ATR 高于过去一段时间均值说明波动开始释放。RSI 不过热作为入场确认RSI 高于 50 但不极端避免追在情绪顶点。注意这只是研究示例不是推荐信号。关键不在于具体参数而在于信号之间形成了“互相确认”的关系。任何一个单独信号都存在大量误报叠加条件后误报率会明显下降但代价是交易机会变少。这恰好就是我们要的“少而准”。2.3 离场和仓位决定了策略能不能长期跑入场设计只解决一半问题离场和仓位设计决定策略的“生存率”。离场规则我一般会分成两类趋势破坏离场均线方向反转或价格跌破关键均线代表逻辑被破坏无条件离场。硬止损离场入场后就设定一个止损位例如 2 倍 ATR 或固定百分比跌破必须执行。仓位规则的关键是“单笔风险固定”。比如你愿意承受单笔亏损不超过总资金的 1%那么合约数量就应该等于“总资金 × 1% ÷ 止损距离”。这样即使连续亏损很多笔整体回撤也可控。这套设计下持仓时间天然不会太长。大部分时间处于空仓状态因为四个条件同时满足的时段本来就少。它不会让你频繁出手也不鼓励你今天进明天出。3. 把“等待”写成代码3.1 研究环境与数据准备在 Python 环境里pandas 和 numpy 基本够用。回测之前你需要一份历史 K 线数据包含 open、high、low、close、volume。这里不接入任何实盘接口只做策略研究。我一般建议先用日线跑通再考虑小时线或分钟线。日线数据量小噪声相对少策略逻辑更容易验证。3.2 示例代码信号生成与逐日状态跟踪下面这段代码是示意结构不构成任何投资建议。它要做的事是默认保持空仓只有趋势、波动、RSI 三个条件同时满足才切换为持仓持仓后如果趋势破坏或触发 2 倍 ATR 止损就回到空仓。import pandas as pd import numpy as np # 假设 df 已包含 open / high / low / close / volume # 这里用随机价格构造示例数据实际使用时替换为你的数据源 np.random.seed(42) n 500 price 100 np.cumsum(np.random.randn(n) * 0.5) df pd.DataFrame({ close: price, high: price np.abs(np.random.randn(n) * 0.3), low: price - np.abs(np.random.randn(n) * 0.3), open: price, }) # 均线 df[ma_fast] df[close].rolling(20).mean() df[ma_slow] df[close].rolling(60).mean() # ATR(14) df[tr] np.maximum( df[high] - df[low], np.maximum( abs(df[high] - df[close].shift(1)), abs(df[low] - df[close].shift(1)) ) ) df[atr] df[tr].rolling(14).mean() # RSI(14)简化版计算 delta df[close].diff() gain delta.clip(lower0) loss -delta.clip(upper0) avg_gain gain.ewm(alpha1/14, min_periods14).mean() avg_loss loss.ewm(alpha1/14, min_periods14).mean() rs avg_gain / avg_loss df[rsi] 100 - 100 / (1 rs) # 三层过滤条件 df[trend_ok] df[ma_fast] df[ma_slow] df[vol_ok] df[atr] df[atr].rolling(20).mean() df[rsi_ok] df[rsi] 50 # 逐日状态模拟 position 0 entry_price None df[position] 0 df[entry_price] np.nan for i in range(len(df)): row df.iloc[i] # 当前空仓看是否满足开仓条件 if position 0: if row[trend_ok] and row[vol_ok] and row[rsi_ok]: position 1 entry_price row[close] # 当前持仓检查离场条件 else: stop_price entry_price - 2 * row[atr] # 趋势破坏或触发止损则离场 if row[close] stop_price or not row[trend_ok]: position 0 entry_price None df.loc[df.index[i], position] position df.loc[df.index[i], entry_price] entry_price if position 1 else np.nan # 统计空仓时间占比 empty_ratio (df[position] 0).mean() print(f空仓时间占比: {empty_ratio:.2%}) trade_signals (df[position].diff() ! 0).sum() print(f状态切换次数: {trade_signals})这段代码里position 等于 1 代表持仓默认是 0 也就是空仓。真正有意思的是即使我加入三个过滤条件在随机数据上它也可能频繁切换因为随机数据没有真实趋势结构。所以回测必须用真实历史数据不能用随机数据来验证策略。3.3 读代码时应该关注哪几个关键点首先空仓是默认状态开仓需要“全条件满足”。其次离场条件不依赖复杂判断只关心趋势是否破坏和止损是否触发。最后这段代码没有包含手续费、滑点和信号延迟很多真实情况还没进来。如果你是从零开始建议先不要改参数先把这段逻辑跑通再看空仓比例和交易次数。跑通之后再慢慢换真实数据加成本加更严格的过滤条件。4. 回测先别急着实盘让历史数据帮你找问题4.1 回测的重点不是收益而是“这策略能不能执行”很多人回测只看一个总收益率这是最大误区。对一个“多数时间空仓”的策略来说更要关注几个指标空仓时间占比是否符合设计目标。交易次数是否少到真的能约束操作。最大回撤极端行情下账户能承受多少亏损。胜率和盈亏比在较少交易次数下单次质量是否足够好。稳定性分年度、分市场状态看策略是否会失效。一个策略如果收益很高但交易次数极少可能存在过拟合问题如果交易频繁但胜率不高则可能只是把成本贡献给了交易所。回测的价值不是证明策略“能赚钱”而是帮助你在实盘前发现问题。4.2 必须避开的回测陷阱回测不等于实盘这是反复要强调的。下面几个陷阱最容易把回测结果变得很好看但实盘完全对不上。未来函数比如用当天的收盘价决定当天是否交易实际执行时你可能要用第二天开盘价。这种回测等于“偷看未来”。前视偏差用全样本数据计算参数再在同一段数据上回测策略天然会“知道”最优参数。解决方法是做样本内和样本外切分。幸存者偏差如果回测到的是现在还活着的标的就会忽略已经退市或暴跌的标的结果被高估。手续费和滑点设置过低尤其对高频策略成本是最大变量。保守估计应该让成本明显高于真实情况看策略还能不能活。参数过拟合不断调参数让历史曲线变漂亮最终会得到一个“只在历史上有效”的策略。判断过拟合的一个简单方法参数稍微偏移一点点结果是否剧烈变化。如果剧烈变化说明这个策略对参数太敏感。4.3 回测流程和判断标准我建议按照以下顺序来跑一轮回测而不是上来就追求收益曲线好看数据清洗检查缺失值、停牌、复权、异常跳空。信号生成用统一的规则和参数同时记录信号时间。模拟撮合考虑信号延迟、涨跌停限制、成交量限制。成本模型手续费、滑点、买卖价差尽量保守。权益曲线计算每日资金变化不要只看期末值。统计指标上面提到的空仓比例、交易次数、最大回撤等。敏感性测试围绕参数中心值上下偏移 20% 到 50%观察结果稳定性。样本外验证把数据切两段前 70% 调参后 30% 验证。回测流程中新手和进阶做法差别很大可以列成一张表检查项新手做法进阶做法数据范围一份历史 K 线从头跑到尾分样本内、样本外覆盖不同市场状态交易成本忽略或按最低费率加入滑点、流动性、冲击成本估计信号执行当天收盘价直接成交次日开盘或考虑信号确认延迟参数设定固定一组参数多组参数做敏感性分析判断标准只看总收益关注回撤、稳定性、交易频率、空仓比例风险验证不测极端行情做压力测试观察连续亏损下账户回撤注意回测结果只要是历史数据就一定存在“欺骗性”。真正的验证是把参数固定住连续跑一段时间模拟盘再决定是否进入小资金实盘。5. 从“策略研究”到“程序化执行”5.1 部署与数据链路代码跑通、回测满意后如果还想继续往前走就面临工程化问题。你不可能每天手动算一遍信号也不可能靠盯盘来执行止损。这时候需要一个简单的程序化执行链路。常见结构是定时任务定时拉取最新数据重新计算信号如果满足入场条件就发出通知如果不满足就保持空仓。把“空仓”也写进逻辑里意味着程序默认什么都不做而不是每次都尝试找一个买卖点。数据链路要关注数据源是否稳定、有没有缺失、复权方式是否一直一致、信号计算是否用到未来数据。这些都需要日志记录。5.2 监控与异常处理程序化执行最大的敌人不是策略失效而是程序静默失败。常见故障包括数据源连接中断导致今天的信号没算。定时任务没触发没人发现。持仓状态和程序记录不一致无法正确判断离场。网络异常导致止损单没有及时发出。因此必须做三件事留日志、做告警、加熔断。日志记录每次信号判断的输入和输出告警在任务失败、数据异常、持仓状态不一致时通知你熔断在连续亏损达到预设阈值时自动停止策略防止情绪化加仓。5.3 人的定位复盘和边界控制即使有程序也绝不是“躺着赚钱”。人的核心工作变成定期复盘策略表现检查参数是否失效确认市场环境是否发生结构性变化。比如趋势策略在单边行情里天然优势明显但进入长期震荡后就会连续小额亏损。这时候不是程序出了问题而是策略和环境的匹配关系变了。我见过很多人把“程序化”理解成“永不干预”结果在策略已经严重违背当前市场状态时还继续运行。正确做法是设置一个“策略生命周期管理”定期检查回撤、连续亏损次数、参数敏感性。当策略表现显著偏离历史分布时先停掉再做归因而不是继续硬扛或随手改参数。5.4 适用边界与前置条件这类“多数时间空仓”的策略适合的场景是你已经有一套明确的交易逻辑希望在执行层面减少情绪干扰用相对低频的方式参与趋势行情。它不适合追求短期高收益的人也不适合没有数据源、没有程序基础的人直接裸跑。它对人的要求也很具体你首先要接受“空仓是常态”这个设定。如果你的目标是每天都要产生交易那这套策略会很不舒服。反过来如果你觉得频繁操作是一种负担它反而能帮你把交易频率降下来。落地时最容易出问题的几个环节按顺序排查数据是否最新、信号计算是否包含未来数据、手续费和滑点是否被低估、持仓状态和程序状态是否一致、止损是否真的会执行。先解决这些再谈优化参数。工程经验是先跑通最小流程再增加复杂性。用模拟盘连续运行两到三周每天检查日志确认没有数据断档、信号计算错误和状态丢失再考虑小资金实盘。这一步跳过得越多后面踩的坑越深。写在最后的经验把策略设计成“80%时间空仓”之后你会发现自己的时间、情绪和决策负担都在下降。对很多人来说“空仓等待”比“频繁交易”更难做到但程序能帮你把这件事自动化。你真正要修炼的不是抓住机会的敏锐度而是面对大量无效行情时敢于不动的定力。策略本身只是工具纪律才是底层能力。用代码固化纪律用回测验证纪律用工程化保障纪律这条路比寻找一个“必胜指标”要慢但它更值得长期投入。第一次跑通“空仓比例 80%”的那天你可能会觉得这个策略太无聊了但恰是这份无聊才是它真正的价值所在。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门