【量化策略】波动指数-用Python检测范围和趋势市场
Backtrader 策略实例
- [Backtrader]实例:均线策略[Backtrader] 实例:MACD策略[Backtrader] 实例:KDJ 策略
- [Backtrader] 实例:RSI 与 EMA 结合
- [Backtrader] 实例:SMA自定义数据源
- [Backtrader] 实例:海龟策略[Backtrader] 实例:网格交易[Backtrader] 实例: 配对交
- [Backtrader] 机器学习预测市场走势与回测
波动率 和 ATR
在深入研究波动指数之前,了解两个关键概念很重要:波动率和平均真实范围 (ATR)。波动率衡量价格波动的幅度。较高的波动性表明风险增加,反之亦然。掌握这个概念可以为交易者提供显着的市场优势。尽管有许多工具可用于测量波动性,但没有一种工具可以达到完美的精度。一个可靠的选择是平均真实范围 (ATR)。
ATR 由 Wilder Wiles 开发,量化资产的平均变动。作为一个滞后指标,它依靠历史数据来衡量当前值,但无法预测未来的价格点。虽然这种滞后性质不一定是缺点,但了解其含义至关重要。ATR 也是无方向性的,这意味着它的值与实际价格趋势成反比。
文章来源:Choppiness Index: Detect Ranging & Trending Markets with Python。在原文基础上做以下修改:
- 数据源读取本地csv,增加函数get_stock_data_csv()
- 对函数get_ci()进行修改增加了atr计算
计算平均真实范围 (ATR)
ATR 计算包括两个步骤: 1. 确定真实范围 (TR):真实范围由以下三个价格差异中的最大值得出 - Current High - Current Low - 当前最高价减去前一日收盘价(Current High minus Previous Close) - 前一收盘价减去当前最低价(Previous Close minus Current Low)
这可以表示为:
MAX [ {HIGH - LOW}, {HIGH - P.CLOSE}, {P.CLOSE - LOW} ]
where,
MAX = Maximum values
HIGH = Market High
LOW = Market Low
P.CLOSE = Previous market close
- 计算 ATR:ATR 是通过在指定周期数内对 True Range 值进行平滑平均来获得的。虽然原始的 ATR 公式使用由 Wiles 创建的自定义移动平均线,但也可以应用其他类型的移动平均线(例如 SMA、EMA)。为简单起见,我们将使用简单移动平均线 (SMA),其传统设置为 14 个周期:
ATR 14 = SMA 14 [ TR ]
where,
ATR 14 = 14 Period Average True Range
SMA 14 = 14 Period Simple Moving Average
TR = True Range
当使用 ATR 作为交易指标时,必须谨慎,因为它往往落后于价格走势。现在我们对波动率和 ATR 有了深入的了解,让我们继续讨论本文的主要重点:波动指数。
波动指数
波动指数是一种波动性指标,用于确定市场是趋势还是波动。它与平均真实范围 (ATR) 具有相似的特性,既是滞后指标又是非方向指标。当波动指数值较高时,它表明市场处于盘整阶段,而较低的值则表明价格走势强劲或势头强劲。
波动指数的计算
波动指数的计算包括两个主要步骤: 1. 计算 ATR:首先确定资产的 ATR,使用 1 作为指定的回溯期。 2. 计算波动指数:要使用 14 天的传统回溯期计算波动指数: - 首先,确定 14 天 ATR 总和与 14 天最高点和 14 天最低点之间的差值的对数(以 10 为基数)。 - 将此值除以回溯期的对数(以 10 为底)。 - 最后,将结果乘以 100。
公式可以表示如下:
CI14 = 100 * LOG10 [14D ATR1 SUM/(14D HIGHH - 14D LOWL)] / LOG10(14)
where,
CI14 = 14-day Choppiness Index
14D ATR1 SUM = 14-day sum of ATR with 1 as lookback period
14D HIGHH = 14-day highest high
14D LOWL - 14-day lowest low
对波动指数的理论解释到此结束。现在,我们继续在 Python 中实现,我们将从头开始编写指标代码。
Python 中的实现
首先,我们将必要的包导入到我们的 Python 环境中。eodhd 包将用于提取历史股票数据,而 Pandas 和 NumPy 将处理数据格式化和复杂功能。此外,Matplotlib 将用于可视化,Math 将协助数学运算。
步骤 1:导入包
按如下方式导入基本包:
# Importing Packages
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import pandas_ta as ta
#from termcolor import colored as cl
from math import floor
#from eodhd import APIClient
# Set plotting parameters
plt.rcParams['figure.figsize'] = (20,10)
plt.style.use('fivethirtyeight')
步骤 2:激活 API 密钥
要使用 EODHD 的 API 功能,必须激活您的 API 密钥。如果您还没有 EODHD API 密钥,您可以通过在网站上注册来获取一个。完成注册后,导航到您账户中的 Dashboard 以检索您的唯一 API 密钥。将此密钥保密并且不与任何人共享至关重要。
# Activating the EODHD API Key
api_key = '<YOUR API KEY>'
client = APIClient(api_key)
第 3 步:提取历史数据
在提取历史数据之前,了解它包含的内容非常重要。历史数据,也称为日终 (EOD) 数据,是在指定时间段内累积的信息集合。它提供对过去价格走势的洞察,帮助识别模式和趋势,并支持深入的市场分析。
使用 EODHD 的 eodhd 包,您可以使用以下代码片段轻松检索任何可交易资产的历史数据:
# EXTRACTING HISTORICAL DATA
def get_historical_data(ticker, start_date):
json_resp = client.get_eod_historical_stock_market_data(symbol = ticker, period = 'd', from_date = start_date, order = 'a')
df = pd.DataFrame(json_resp)
df = df.set_index('date')
df.index = pd.to_datetime(df.index)
return df
def get_stock_data_csv():
stock = pd.read_csv('./data.csv',parse_dates=['Date'])
stock['Date'] = pd.to_datetime(stock['Date'], utc=True).dt.tz_localize(None)
stock = stock.set_index('Date')
return stock
apple = get_stock_data_csv()
apple.tail()
Open | High | Low | Close | Volume | Dividends | Stock Splits | |
---|---|---|---|---|---|---|---|
Date | |||||||
2024-12-11 05:00:00 | 247.960007 | 250.800003 | 246.259995 | 246.490005 | 45205800 | 0.0 | 0.0 |
2024-12-12 05:00:00 | 246.889999 | 248.740005 | 245.679993 | 247.960007 | 32777500 | 0.0 | 0.0 |
2024-12-13 05:00:00 | 247.820007 | 249.289993 | 246.240005 | 248.130005 | 33155300 | 0.0 | 0.0 |
2024-12-16 05:00:00 | 247.990005 | 251.380005 | 247.649994 | 251.039993 | 51694800 | 0.0 | 0.0 |
2024-12-17 05:00:00 | 250.080002 | 253.830002 | 249.779999 | 253.479996 | 51321700 | 0.0 | 0.0 |
- get_historical_data 函数旨在获取给定股票行情和开始日期的历史股票数据。
- ticker:股票的代码(例如,“TSLA”代表 Tesla)。
- period:指定数据点的频率(在本例中为 'd' 表示每日)。
- from_date:表示数据的开始日期(格式:“YYYY-MM-DD”)。
- order:可选参数,用于根据日期按升序 ('a') 或降序 ('d') 排列数据。
第 3 步:波动指数计算
在此步骤中,我们将按照前面解释的公式,使用 14 天的回溯期计算波动指数 (CI) 值。
def get_ci(high, low, close, lookback):
tr1 = pd.DataFrame(high - low).rename(columns = {0:'tr1'})
tr2 = pd.DataFrame(abs(high - close.shift(1))).rename(columns = {0:'tr2'})
tr3 = pd.DataFrame(abs(low - close.shift(1))).rename(columns = {0:'tr3'})
frames = [tr1, tr2, tr3]
tr = pd.concat(frames, axis = 1, join = 'inner').dropna().max(axis = 1)
atr = tr.rolling(window=lookback).mean()
highh = high.rolling(lookback).max()
lowl = low.rolling(lookback).min()
ci = 100 * np.log10((atr.rolling(lookback).sum()) / (highh - lowl)) / np.log10(lookback)
return ci
apple['ci_14'] = get_ci(apple['High'], apple['Low'], apple['Close'], 14)
apple = apple.dropna()
apple.tail()
Open | High | Low | Close | Volume | Dividends | Stock Splits | ci_14 | |
---|---|---|---|---|---|---|---|---|
Date | ||||||||
2024-12-11 05:00:00 | 247.960007 | 250.800003 | 246.259995 | 246.490005 | 45205800 | 0.0 | 0.0 | 26.132118 |
2024-12-12 05:00:00 | 246.889999 | 248.740005 | 245.679993 | 247.960007 | 32777500 | 0.0 | 0.0 | 29.392818 |
2024-12-13 05:00:00 | 247.820007 | 249.289993 | 246.240005 | 248.130005 | 33155300 | 0.0 | 0.0 | 31.880874 |
2024-12-16 05:00:00 | 247.990005 | 251.380005 | 247.649994 | 251.039993 | 51694800 | 0.0 | 0.0 | 37.273008 |
2024-12-17 05:00:00 | 250.080002 | 253.830002 | 249.779999 | 253.479996 | 51321700 | 0.0 | 0.0 | 33.089960 |
get_ci 的函数,该函数将最高价 (high)、最低价 (low)、收盘价 (close) 和回溯期作为输入参数。
在该函数中,我们计算真实范围 (TR) 计算所需的三个差值。为了获得 TR,我们使用 Pandas max 函数从这三个差异中选择最大值。回溯期为 1 时,我们使用滚动和均值函数计算 TR 的简单移动平均线 (SMA),以获得平均真实范围 (ATR),并将其存储在变量 atr 中。接下来,我们定义两个变量 — highh 和 lowl — 来捕获给定回溯期的最高最高价和最低价。之后,我们将所有这些计算值代入 Choppiness Index 公式,以获得指标的值。
使用 Choppiness Index
Choppiness Index 值的范围介于 0 和 100 之间,使其成为范围受限的振荡器。值越接近 100,市场的波动性 (范围) 就越高,反之亦然。通常,在波动指数的上方和下方绘制两个水平水平,以帮助确定市场是波动还是趋势。上限设定在 61.8 的阈值,如果波动指数达到或超过该水平,则认为市场正在盘整。相反,下限设置为 38.2,如果指数跌至或低于该水平,则认为市场处于趋势中。
Choppiness Index 的用法可以总结如下:
IF CHOPPINESS INDEX >= 61.8 --> MARKET IS CONSOLIDATING
IF CHOPPINESS INDEX <= 38.2 --> MARKET IS TRENDING
Python 实现:
ax1 = plt.subplot2grid((11,1,), (0,0), rowspan = 5, colspan = 1)
ax2 = plt.subplot2grid((11,1,), (6,0), rowspan = 4, colspan = 1)
ax1.plot(apple['Close'], linewidth = 2.5, color = '#2196f3')
ax1.set_title('apple CLOSING PRICES')
ax2.plot(apple['ci_14'], linewidth = 2.5, color = '#fb8c00')
ax2.axhline(38.2, linestyle = '--', linewidth = 1.5, color = 'grey')
ax2.axhline(61.8, linestyle = '--', linewidth = 1.5, color = 'grey')
ax2.set_title('apple CHOPPINESS INDEX 14')
plt.show()
该图表分为两个部分:顶部面板显示特斯拉的收盘价,而底部面板显示 14 天的波动指数值。波动指数上方和下方绘制的两条水平线表示用于识别市场行为的阈值。由于特斯拉的高波动性和大幅的价格波动,波动指数经常跌破 38.2 的下限,表明势头强劲且波动性增加。这些读数可以通过观察相应的价格走势来交叉验证。相反,当波动指数升至 61.8 的上限阈值以上时,表明特斯拉正在整合。这种方法是利用波动指数分析真实市场的标准方法。
最后的思考
在彻底涵盖了理论和实施之后,我们对波动指数、其计算和实际应用有了深入的了解。虽然它看起来是一个简单的指标,但它在交易中非常有价值,因为它可以帮助避免不必要的损失。但是,由于其滞后性,在使用它进行交易决策时要谨慎行事至关重要。波动指数不应作为确定进入和退出点的唯一基础,而应用作更大交易策略中的补充过滤器。在实际交易场景中应用波动指数时,有两个关键考虑因素:
- 策略优化:波动指数的有效性不仅仅是较高和较低的阈值。必须有一个经过充分优化的交易策略来有效利用该指标。在将策略应用于实际交易之前,请务必改进您的策略。
- 回溯测试:仅在一项资产上测试策略可能不会产生可靠的结果,并可能导致不可预见的结果。市场是不可预测的,并且并不总是以相同的方式运行。为了提高策略的可靠性,请在不同的资产中对其进行回溯测试,并根据需要进行调整。