作者:老余捞鱼
原创不易,转载请标明出处及原作者。
写在前面的话:在这篇文章里,我详细分享了如何用Python优化算法交易中的RSI指标。通过调整周期、超买/超卖阈值和止损百分比,显著提升了交易策略的表现。结合苹果股票数据的回测结果,效果一目了然!如果你也想提高交易绩效,这些实用技巧绝对不容错过,赶紧来学习吧!
一、优化 RSI 指标
1.1 什么是 RSI ?
RSI (Relative Strength Index)是一种动量震荡指标,用于测量价格变动的速度和变化。它在 0 和 100 之间震荡,通常在图表上显示为一条线,随着资产价格的变动而变动。
RSI 的计算公式为:RSI = 100 × RS / (1 + RS),其中RS = N天内收市价上涨数之和的平均值 / N天内收市价下跌数之和的平均值。
1.2 RSI 应用
RSI 是一种动量震荡指标,通过评估价格变动的速度和幅度,帮助判断市场的超买或超卖状态。当 RSI 低于 30 时,可能暗示着买入机会;而当 RSI 超过 70,则可能是卖出的信号。
- 超买与超卖:通常,RSI值超过70被认为市场处于超买状态,可能面临回调或下跌压力;而RSI值低于30则被视为超卖状态,可能即将出现反弹或上涨。
- 趋势判断:RSI值大于50通常表示市场处于多方市场(即上涨趋势),而小于50则表示市场处于空方市场(即下跌趋势)。
- 交叉信号:短期RSI(如6日RSI)与长期RSI(如12日RSI)的交叉情况可以提供交易信号。当短期RSI从下向上突破长期RSI时,视为买入信号;反之,从上向下突破时,则为卖出信号。
- 背离现象:当资产价格继续上涨而RSI不再创新高,或价格继续下跌而RSI不再创新低时,这种背离现象可能预示着市场趋势的即将逆转。
1.3 优化RSI
如果运用得当,RSI 指标能够通过精准识别买卖点,显著提升算法交易策略的盈利能力。然而,默认参数(比如常见的 14 天周期)并不适合所有市场或资产,优化调整才能发挥最大效果。优化 RSI 涉及调整其参数,比如周期和超买/超卖阈值,以提高策略性能。
- RSI 周期:调整周期长度会极大地影响指标对价格变动的反应能力。周期越短可能越敏感,产生的信号越多,但噪音也越大。周期越长,信号越平滑,但可能会错过市场方向的快速变化。
- 超买/超卖阈值:标准的超买/超卖水平是 70 和 30,但通过历史数据优化这些阈值,可以更精准地捕捉市场状态。
如果你能深入理解这两个指标,并掌握优化它们性能的方法,就能灵活运用 RSI,实现交易利润的最大化!
二、Python 优化 RSI
2.1 计算 RSI
下图为苹果(AAPL)股票价格与 RSI 的对比图。
我们可用使用下面的 Python 代码实现,并根据需要调整时间段。
import yfinance as yf
import pandas as pd
import matplotlib.pyplot as plt
def calculate_rsi(data, period=14):
"""
Calculate the Relative Strength Index (RSI).
:param data: DataFrame with 'Close' column containing closing prices.
:param period: Period for calculating RSI, default is 14.
:return: DataFrame with RSI values.
"""
delta = data['Close'].diff(1)
gain = delta.where(delta > 0, 0)
loss = -delta.where(delta < 0, 0)
avg_gain = gain.rolling(window=period).mean()
avg_loss = loss.rolling(window=period).mean()
rs = avg_gain / avg_loss
rsi = 100 - (100 / (1 + rs))
data['RSI'] = rsi
return data
def plot_rsi(data, ticker):
"""
Plot closing prices and RSI.
:param data: DataFrame with 'Close' and 'RSI' columns.
:param ticker: Stock ticker symbol for the title.
"""
fig, axes = plt.subplots(2, figsize=(12, 8), sharex=True)
# Plot closing price
axes[0].plot(data.index, data['Close'], label='Close Price')
axes[0].set_title(f'{ticker} Closing Prices')
axes[0].set_ylabel('Price')
axes[0].legend()
# Plot RSI
axes[1].plot(data.index, data['RSI'], label='RSI', color='orange')
axes[1].axhline(70, color='red', linestyle='--', label='Overbought (70)')
axes[1].axhline(30, color='green', linestyle='--', label='Oversold (30)')
axes[1].set_title(f'{ticker} RSI')
axes[1].set_ylabel('RSI')
axes[1].set_xlabel('Date')
axes[1].legend()
plt.tight_layout()
plt.show()
# Fetch stock data
ticker = "AAPL" # Replace with your preferred stock ticker
data = yf.download(ticker, start="2014-01-01", end="2024-01-01")
data_clean = data.copy()
data_clean = data_clean.ffill()
data_clean.columns = ['Adj Close','Close','High','Low','Open','Volume']
data = data_clean.copy()
# Calculate RSI
data = calculate_rsi(data)
# Plot RSI
plot_rsi(data, ticker)
calculate_rsi
函数会根据指定时间段(默认 14 天)的股票收盘价计算 RSI 值。它通过比较平均涨幅和平均跌幅的比例,生成一个 0 到 100 之间的震荡指标,帮助判断市场状态。
2.2 回测 RSI 交易策略
计算出 RSI 值后,我们可以通过回溯测试模拟策略的历史表现。具体规则是:当 RSI 从下方突破超卖水平(通常为 30)时买入,当 RSI 从上方跌破超买水平(通常为 70)时卖出。
def backtest_rsi(data, rsi_period=14, overbought=70, oversold=30, stop_loss_pct=0.05, initial_balance=10000):
data = calculate_rsi(data, period=rsi_period)
balance = initial_balance
position = 0
entry_price = 0
for i in range(1, len(data)):
row = data.iloc[i]
prev_row = data.iloc[i - 1]
# Buy signal: RSI crosses above the oversold level
if position == 0 and prev_row['RSI'] < oversold and row['RSI'] >= oversold:
position = balance / row['Close']
entry_price = row['Close']
balance = 0
# Sell signal: RSI crosses below the overbought level or stop-loss triggered
elif position > 0:
stop_loss_price = entry_price * (1 - stop_loss_pct)
if (row['RSI'] <= overbought and prev_row['RSI'] > overbought) or row['Close'] <= stop_loss_price:
balance = position * row['Close']
position = 0
if position > 0:
balance += position * data.iloc[-1]['Close']
return balance
在这个功能中,我们将使用历史股票数据进行回溯测试。模拟策略从初始资金(例如 10,000 美元)开始,根据 RSI 信号执行买卖操作。为了有效管理风险,我们还加入了止损功能:当价格跌破入场价的指定百分比时,自动卖出,避免进一步亏损。
根据默认参数(RSI 周期=14、超买水平=70、超卖水平=30)的回测结果,初始资金从 10,000 美元仅增长到 10,167 美元,表现平平,甚至不如简单的“买入并持有”策略。显然,我们需要优化参数,找到更佳的组合来提升策略效果。
2.3 优化 RSI 参数
下一步是找到 RSI 关键参数的最佳值,如 RSI 周期、超买和超卖水平,以及止损百分比。我们通过一个优化函数来探索这些参数的各种组合,从而实现这一目标:
from itertools import product
def optimize_rsi(data, rsi_periods, overbought_levels, oversold_levels, stop_loss_pcts):
results = []
for rsi_period, overbought, oversold, stop_loss_pct in product(rsi_periods, overbought_levels, oversold_levels, stop_loss_pcts):
if overbought <= oversold:
continue # Skip invalid combinations
final_balance = backtest_rsi(data, rsi_period, overbought, oversold, stop_loss_pct)
results.append({
'RSI Period': rsi_period,
'Overbought Level': overbought,
'Oversold Level': oversold,
'Stop Loss %': stop_loss_pct,
'Final Balance': final_balance
})
results_df = pd.DataFrame(results)
return results_df
# Optimize RSI parameters
rsi_periods = range(5, 21, 1) # RSI periods from 5 to 20
overbought_levels = range(65, 86, 5) # Overbought levels from 65 to 85
oversold_levels = range(15, 36, 5) # Oversold levels from 15 to 35
stop_loss_pcts = [0.02, 0.05, 0.1] # Stop-loss percentages
results_df = optimize_rsi(data, rsi_periods, overbought_levels, oversold_levels, stop_loss_pcts)
# Find the best parameters
best_params = results_df.loc[results_df['Final Balance'].idxmax()]
print("Best Parameters:")
print(best_params)
# Plot optimization results
plot_optimization_results(results_df)
我们利用 itertools.product
函数遍历所有可能的参数组合。针对每一种组合,都会运行一次回溯测试,并将最终的账户余额记录在 DataFrame 中,方便后续分析和比较。
2.4 优化结果可视化
优化参数后,我们需要将结果可视化,以便快速找到最佳组合。比如,可以通过创建热图来直观展示不同参数设置下的最终账户余额变化,帮助我们锁定最有利的策略配置。
def plot_optimization_results(results_df):
pivot = results_df.pivot_table(
index='RSI Period',
columns='Overbought Level',
values='Final Balance',
aggfunc='max'
)
plt.figure(figsize=(10, 8))
plt.title("Optimization Results: Final Balance")
sns.heatmap(pivot, annot=True, fmt=".2f", cmap="viridis")
plt.xlabel("Overbought Level")
plt.ylabel("RSI Period")
plt.show()
最佳建议参数
- RSI 周期:12
- 超买水平:85
- 超卖水平:35
- 止损 % : 0.1
- 最终余额 : 59341.05
这张热图展示了最终账户余额如何随 RSI 周期和超买水平的不同组合而变化。但由于只有两个维度,超卖水平这一关键参数未能充分体现。为了更好地分析,我们将切换到三维图,全面展示参数之间的关系。
2.5 增强可视化的 3D 绘图
如果需要更详细的分析,可以使用三维散点图,将最终账户余额与 RSI 周期、超买水平和超卖水平进行对比,从而更全面地评估参数组合的效果。
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
def plot_3d_optimization_results(results_df):
"""
Plot the optimization results in 3D.
"""
fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111, projection='3d')
# Extract data for the plot
rsi_period = results_df['RSI Period']
overbought = results_df['Overbought Level']
oversold = results_df['Oversold Level']
final_balance = results_df['Final Balance']
# Create a scatter plot
scatter = ax.scatter(rsi_period, overbought, oversold, c=final_balance, cmap='viridis', alpha=0.8)
# Add labels and title
ax.set_title('3D Optimization Results: Final Balance', pad=20)
ax.set_xlabel('RSI Period', labelpad=10)
ax.set_ylabel('Overbought Level', labelpad=10)
ax.set_zlabel('Oversold Level', labelpad=10)
# Add color bar for balance
cbar = fig.colorbar(scatter, ax=ax, shrink=0.6, aspect=10)
cbar.set_label('Final Balance')
plt.show()
# Plot the 3D optimization results
plot_3d_optimization_results(results_df)
这种三维图可以更详细地显示参数之间的相互作用以及最终的平衡,帮助交易者做出数据驱动的决策。
我们可以使用之前编码的 backtest_rsi 函数查看更详细的回溯测试结果,如下图所示。
# Backtest with best parameters
_, _, best_equity_curve = backtest_rsi(
data,
rsi_period=12,
overbought=85,
oversold=35,
stop_loss_pct=0.1
)
# Plot equity curve
plot_equity_curve(best_equity_curve)
从优化后的结果来看,初始资金从 10,000 美元增长到了 59,341.05 美元,且最大回撤控制在 25% 以内,表现相当出色。不过从实战出发,如果选择买入并持有 AAPL 股票 10 年,尽管波动风险更高,但收益可能更为可观。
三、观点总结
在构建交易系统时,有一个关键原则必须牢记:在将系统投入实际交易之前,一定要进行前向优化测试。只有这样,才能确保您的系统和参数在当前市场中依然有效,避免盲目部署带来的风险。
- RSI 是衡量价格变动速度和变化的重要指标,对于识别交易机会至关重要。
- 默认的 RSI 参数可能需要根据具体市场和资产进行调整,以提高策略的有效性。
- 回溯测试是评估和优化交易策略的关键工具,可以帮助交易者了解历史表现并调整策略。
- 优化 RSI 参数可以显著提高交易策略的盈利能力,尤其是通过调整 RSI 周期、超买/超卖阈值和止损机制。
- 可视化优化结果有助于交易者做出更明智的决策,热图和三维散点图是两种有效的可视化方法。
- 前向优化是确保交易系统在实际市场中有效性的重要步骤,应在实际交易之前进行。
- 交易者应该持续学习和适应市场变化,以保持交易策略的相关性和盈利能力。
感谢您阅读到最后,希望这篇文章为您带来了新的启发和实用的知识!如果觉得有帮助,请不吝点赞和分享,您的支持是我持续创作的动力。祝您投资顺利,收益长虹!如果对文中内容有任何疑问,欢迎留言,我会尽快回复!
本文内容仅限技术探讨和学习,不构成任何投资建议。