问题描述
如何计算的得到和主流厂家相等或接近的指标。
我尝试了talib库的SAR函数,
talib.SAR(df.high.values,df.low.values,acceleration=0.02, maximum=0.2)
虽然知道传入high,low序列的长度不一样得到的结果不一样。
但无论传10天, 20天, 30天, 100天,似乎都和通达信的都不太一样。
SRA这个指标一般你们都怎么算? 参数如何设定?
解决方案
为什么 talib 计算的 SAR 和通达信不一样?
在使用 talib.SAR 计算抛物线转向(SAR)指标时,很多量化开发者会发现结果与国内主流炒股软件(如通达信、同花顺)存在差异。这主要由以下两个原因导致:
1. SAR 指标的“递归”特性(最核心原因)
SAR 是一个典型的路径依赖(递归)指标。今天的 SAR 值是由昨天的 SAR 值、昨天的极值(EP)以及加速因子(AF)共同决定的。这意味着,计算的起点不同,得到的结果就会完全不同。
通达信等主流软件在展示 SAR 时,通常是从该股票上市的第一天(或者软件本地缓存的极长历史数据,如几年甚至十几年)开始计算的。而你在策略中如果只传入 10天、30天 甚至 100天的数据,talib 只能以这短短几十天的数据作为起点进行初始化,这必然导致当前的 SAR 值与通达信产生巨大偏差。
2. 初始值的设定逻辑
talib 和通达信在第一天的 SAR 初始值设定上可能存在微小的逻辑差异,但只要经过足够长时间的迭代,这种初始误差会被逐渐抹平(收敛)。
如何解决?(参数设定与计算方法)
要得到与通达信高度接近的 SAR 指标,核心秘诀是:利用长周期数据进行“预热”。
参数设定
通达信 SAR 的默认参数通常是 (10, 2, 20),对应的含义是:
- 加速因子步长 (Step):2% -> 对应
talib中的acceleration=0.02 - 加速因子最大值 (Max):20% -> 对应
talib中的maximum=0.2
正确的计算姿势
不要只传 30 天或 100 天的数据。建议至少传入过去 300 天到 500 天的数据给 talib.SAR,让指标有足够的时间进行递归收敛。然后,你只需要取计算结果的最后几个值即可。经过 300 天以上的迭代,talib 的结果通常会与通达信精确到小数点后两位。
JoinQuant 代码示例
以下是在 JoinQuant 平台中获取与通达信一致的 SAR 指标的代码示例:
import talib
import numpy as np
from jqdata import *
def initialize(context):
g.security = '000001.XSHE'
set_benchmark('000300.XSHG')
# 必须使用真实价格(前复权),因为通达信默认也是前复权
set_option('use_real_price', True)
run_daily(market_open, time='09:30')
def market_open(context):
# 秘诀:获取过去 400 天的最高价和最低价数据进行“预热”
# 数据量越大,越接近通达信,但为了性能,400天通常足够收敛了
df = attribute_history(g.security, 400, '1d', ['high', 'low'], skip_paused=True)
if len(df) < 400:
log.warn("数据不足 400 天,SAR 可能存在误差")
high_prices = df['high'].values
low_prices = df['low'].values
# 使用 talib 计算 SAR
# acceleration=0.02, maximum=0.2 对应通达信默认参数
sar_values = talib.SAR(high_prices, low_prices, acceleration=0.02, maximum=0.2)
# 我们只需要最新的那一个 SAR 值
current_sar = sar_values[-1]
previous_sar = sar_values[-2]
current_close = attribute_history(g.security, 1, '1d', ['close'])['close'][-1]
log.info(f"昨日 SAR: {previous_sar:.2f}, 今日 SAR: {current_sar:.2f}, 当前收盘价: {current_close:.2f}")
# 简单的 SAR 策略逻辑:价格向上突破 SAR 买入,向下突破 SAR 卖出
if current_close > current_sar and context.portfolio.positions[g.security].closeable_amount == 0:
order_value(g.security, context.portfolio.available_cash)
log.info("价格突破 SAR,买入")
elif current_close < current_sar and context.portfolio.positions[g.security].closeable_amount > 0:
order_target(g.security, 0)
log.info("价格跌破 SAR,卖出")
总结
- 参数:
acceleration=0.02, maximum=0.2是正确的。 - 数据长度:将传入
talib.SAR的数据长度增加到 300~500天。 - 复权方式:确保你获取的数据是前复权数据(JoinQuant 默认即为前复权,开启
use_real_price=True即可),因为通达信的指标通常也是基于前复权 K 线计算的。如果不复权,遇到分红派息时 SAR 会出现严重失真。