Python Pandas 如何在条件逻辑中通过ffill()存储值实现交易止损
核心实现逻辑校准
原代码的核心问题
- 类型错配:逐行循环中定义的
cor_price是Python原生标量,根本没有ffill()方法,这是触发属性报错、无法完成价格填充的直接原因。 - 逻辑错位:开仓瞬间就执行止损判断,相当于刚完成买入就立刻平仓,完全没有覆盖持仓周期内的逐日价格跟踪。
- 状态跟踪断裂:没有独立标记“持仓/空仓”的全局状态,导致价格填充的锚点混乱,ffill会无差别把旧价格延续到空仓阶段,不符合交易规则。
可直接运行的实现流程
- 先向量化计算MACD金叉信号,避免逐行判断的性能损耗
# 匹配样本数据的列名,计算金叉:MACD从低于信号线变为高于信号线的时刻 df['macd_cross_up'] = ( (df['MACD'] > df['MACD_SIGNAL']) & (df['MACD'].shift(1) <= df['MACD_SIGNAL'].shift(1)) ) - 逐行追踪交易状态,明确标记持仓周期
current_pos = 0 # 0=空仓,1=持仓 entry_price = None df['position'] = 0 for idx, row in df.iterrows(): # 空仓状态下遇到金叉 → 开仓,记录买入价 if row['macd_cross_up'] and current_pos == 0: current_pos = 1 entry_price = row['PRICE'] # 持仓状态下逐日检查止损条件 elif current_pos == 1 and entry_price is not None: current_diff = (row['PRICE'] - entry_price) / entry_price # 跌幅达到5% → 触发止损,切回空仓 if current_diff <= -0.05: current_pos = 0 entry_price = None # 把当前交易状态写回DataFrame df.loc[idx, 'position'] = current_pos - 构造适合ffill()的基准价格列
# 仅在开仓当天记录当日价格作为填充起点,其余位置先设为空值 df['cor_price'] = df['PRICE'].where( (df['position'] == 1) & (df['macd_cross_up']), pd.NA ) # 向前填充,让持仓期间的每一个交易日都继承最近一次开仓的价格 df['cor_price'] = df['cor_price'].ffill() # 清空空仓阶段的填充值,避免旧买入价被带到无持仓的时段 df.loc[df['position'] == 0, 'cor_price'] = pd.NA # 计算持仓期内每日相对买入价的涨跌幅 df['diff_perc'] = (df['PRICE'] - df['cor_price']) / df['cor_price']
避坑提示
- ffill()是pandas Series的专属方法,不要在循环里对单值标量调用该方法,所有填充操作都要基于整列的Series完成。
- 开仓当日的涨跌幅恒为0,止损判断必须从开仓后的下一个交易日开始逐行检查,不要和开仓逻辑写在同一个分支里。
- 填充价格时必须和持仓状态绑定,空仓阶段的
cor_price必须强制置空,否则ffill会跨持仓周期延续旧价格,导致涨跌幅计算完全失真。
内容的提问来源于stack exchange,提问作者doomdaam
相关产品推荐
相关产品推荐

