You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Python Pandas实现多仓位止盈止损回测向量化优化

海量行情数据回测:向量化实现多仓位止盈止损出场计算

我用Python Pandas处理本地700万+行的市场数据做策略回测,入场信号已实现向量化且效率达标。现在需要解决多仓位的止盈止损出场计算问题:每个仓位有独立的止盈(take profit)和止损(stop loss)价格阈值,需为每个开仓记录匹配对应的出场价格和时间。

现有数据结构

带Datetime索引的DataFrame如下:

import pandas as pd
from pandas import Timestamp
import numpy as np

df = pd.DataFrame({
    'open': {Timestamp('2021-01-03 22:11:00'): 1.22319, Timestamp('2021-01-03 22:12:00'): 1.22315, Timestamp('2021-01-03 22:15:00'): 1.22324, Timestamp('2021-01-03 22:16:00'): 1.22355, Timestamp('2021-01-03 22:17:00'): 1.22357}, 
    'high': {Timestamp('2021-01-03 22:11:00'): 1.22319, Timestamp('2021-01-03 22:12:00'): 1.22318, Timestamp('2021-01-03 22:15:00'): 1.22358, Timestamp('2021-01-03 22:16:00'): 1.2236, Timestamp('2021-01-03 22:17:00'): 1.22361}, 
    'low': {Timestamp('2021-01-03 22:11:00'): 1.22317, Timestamp('2021-01-03 22:12:00'): 1.22315, Timestamp('2021-01-03 22:15:00'): 1.22324, Timestamp('2021-01-03 22:16:00'): 1.22352, Timestamp('2021-01-03 22:17:00'): 1.22355}, 
    'close': {Timestamp('2021-01-03 22:11:00'): 1.22317, Timestamp('2021-01-03 22:12:00'): 1.22315, Timestamp('2021-01-03 22:15:00'): 1.22358, Timestamp('2021-01-03 22:16:00'): 1.22352, Timestamp('2021-01-03 22:17:00'): 1.22356}, 
    'longEntrySignal': {Timestamp('2021-01-03 22:11:00'): False, Timestamp('2021-01-03 22:12:00'): False, Timestamp('2021-01-03 22:15:00'): True, Timestamp('2021-01-03 22:16:00'): False, Timestamp('2021-01-03 22:17:00'): False}, 
    'longEntry': {Timestamp('2021-01-03 22:11:00'): False, Timestamp('2021-01-03 22:12:00'): False, Timestamp('2021-01-03 22:15:00'): False, Timestamp('2021-01-03 22:16:00'): True, Timestamp('2021-01-03 22:17:00'): False}, 
    'longEntryPrice': {Timestamp('2021-01-03 22:11:00'): np.nan, Timestamp('2021-01-03 22:12:00'): np.nan, Timestamp('2021-01-03 22:15:00'): np.nan, Timestamp('2021-01-03 22:16:00'): 1.22355, Timestamp('2021-01-03 22:17:00'): np.nan}, 
    'longTpPrice': {Timestamp('2021-01-03 22:11:00'): np.nan, Timestamp('2021-01-03 22:12:00'): np.nan, Timestamp('2021-01-03 22:15:00'): np.nan, Timestamp('2021-01-03 22:16:00'): 1.2243451663854852, Timestamp('2021-01-03 22:17:00'): np.nan}, 
    'longSlPrice': {Timestamp('2021-01-03 22:11:00'): np.nan, Timestamp('2021-01-03 22:12:00'): np.nan, Timestamp('2021-01-03 22:15:00'): np.nan, Timestamp('2021-01-03 22:16:00'): 1.2227548336145146, Timestamp('2021-01-03 22:17:00'): np.nan}})

print(df)

输出:

open    high     low    close  longEntrySignal  longEntry  longEntryPrice  longTpPrice  longSlPrice
2021-01-03 22:11:00  1.22319  1.22319  1.22317  1.22317            False        False              NaN          NaN          NaN
2021-01-03 22:12:00  1.22315  1.22318  1.22315  1.22315            False        False              NaN          NaN          NaN
2021-01-03 22:15:00  1.22324  1.22358  1.22324  1.22358             True        False              NaN          NaN          NaN
2021-01-03 22:16:00  1.22355  1.22360  1.22352  1.22352            False         True           1.22355    1.224345    1.222755
2021-01-03 22:17:00  1.22357  1.22361  1.22355  1.22356            False        False              NaN          NaN          NaN

字段说明:

  • longEntrySignal:标记下一根K线的开多信号(True/False)
  • longEntry:标记当前K线为开仓K线(True/False)
  • longEntryPrice:开仓K线的开盘价,作为开仓成本
  • longTpPrice/longSlPrice:对应仓位的止盈/止损价格阈值

期望输出

新增exitPrice和exitTime列,记录每个仓位的出场信息:

open    high     low    close  longEntrySignal  longEntry  longEntryPrice  longTpPrice  longSlPrice  exitPrice           exitTime
2021-01-03 22:11:00  1.22319  1.22319  1.22317  1.22317            False        False              NaN          NaN          NaN        NaN                 NaN
2021-01-03 22:12:00  1.22315  1.22318  1.22315  1.22315            False        False              NaN          NaN          NaN        NaN                 NaN
2021-01-03 22:15:00  1.22324  1.22358  1.22324  1.22358             True        False              NaN          NaN          NaN        NaN                 NaN
2021-01-03 22:16:00  1.22355  1.22360  1.22352  1.22352            False         True           1.22355    1.224345    1.222755    1.224345  2021-01-03 22:29:00
2021-01-03 22:17:00  1.22357  1.22361  1.22355  1.22356            False        False              NaN          NaN          NaN        NaN                 NaN

规则说明:

  • exitPrice:触发止盈则取longTpPrice,触发止损则取longSlPrice;若同一K线同时触发两者,优先取止损价
  • `exitTime``:触发止盈/止损的K线时间

当前方案与问题

目前筛选开仓行后用apply()调用自定义函数getLongExit计算出场信息:

entryDf = df[df['longEntry']].copy()
entryDf[['exitPrice', 'exitTime']] = entryDf.apply(lambda x: getLongExit(exitDf=df[['high', 'low']], entryPrice=x['longEntryPrice'], entryTime=x.index, takeProfit=x['longTpPrice'], stopLoss=x['longSlPrice']), axis=1, result_type='expand')

getLongExit内部通过.loc、.idxmax()和.idxmin()判断止盈止损的触发顺序,返回对应结果

存在的问题

  1. 效率低下:apply()逐行处理,面对700万+行数据时速度极慢
  2. Numba方案报错:尝试用Numba加速时出现类型错误,错误信息如下:
Traceback (most recent call last):
  File "/Users/maxwitt/PycharmProjects/ForexStrategies/strategy1.py", line 288, in <module>
    get_long_exit(
  File "/Users/maxwitt/PycharmProjects/ForexStrategies/venv/lib/python3.10/site-packages/numba/core/dispatcher.py", line 468, in _compile_for_args
    error_rewrite(e, 'typing')
  File "/Users/maxwitt/PycharmProjects/ForexStrategies/venv/lib/python3.10/site-packages/numba/core/dispatcher.py", line 409, in error_rewrite
    raise e.with_traceback(None)
numba.core.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
No implementation of function Function(<built-in function setitem>) found for signature:
 
 >>> setitem(array(float64, 1d, C), int64, datetime64[ns])
 
There are 16 candidate implementations:
   - Of which 16 did not match due to:
   Overload of function 'setitem': File: <numerous>: Line N/A.
     With argument(s): '(array(float64, 1d, C), int64, datetime64[ns])':
    No match.

During: typing of setitem at /Users/maxwitt/PycharmProjects/ForexStrategies/strategy1.py (167)

File "strategy1.py", line 167:
def get_long_exit(index, high_vals, low_vals, tp_prices, sl_prices, out_exit_price, out_indices):
    <source elided>
                out_exit_price[idx1] = sl_entry
                out_indices[idx1] = index[idx2]
                ^

寻求解决方案

需要高效的向量化实现方案,解决海量数据下的出场计算效率问题,同时修复Numba类型错误。

内容的提问来源于stack exchange,提问作者snky

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 16:40:55