# 如何使用Python實現一個簡單的商品期貨布林指標突破策略
## 一、策略概述
### 1.1 布林帶指標簡介
布林帶(Bollinger Bands)是由約翰·布林格(John Bollinger)在1980年代發明的技術分析工具,由三條線組成:
- 中軌(Middle Band):N日移動平均線(通常為20日SMA)
- 上軌(Upper Band):中軌 + k倍標準差(通常k=2)
- 下軌(Lower Band):中軌 - k倍標準差
該指標通過計算價格的波動區間,反映市場的超買超賣狀態。當價格突破上下軌時,往往預示著趨勢的開始或反轉。
### 1.2 突破策略原理
本策略的基本邏輯是:
1. 當價格**收盤價突破上軌**時,做多入場
2. 當價格**收盤價跌破下軌**時,做空入場
3. 當價格**回歸中軌**時,平倉離場
## 二、環境準備
### 2.1 所需Python庫
```python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import tushare as ts # 獲取金融數據的庫
import talib # 技術指標計算庫
以螺紋鋼期貨(RB9999)為例,獲取歷史數據:
# 使用tushare pro獲取數據(需要注冊獲取token)
pro = ts.pro_api('your_token_here')
# 獲取螺紋鋼主力合約日線數據
df = pro.fut_daily(ts_code="RB9999.SHF", start_date="20200101", end_date="20231231")
df = df.sort_values('trade_date').reset_index(drop=True)
def calculate_bollinger_bands(data, window=20, k=2):
"""
計算布林帶指標
參數:
data: 價格序列
window: 移動平均窗口(默認20)
k: 標準差倍數(默認2)
返回:
DataFrame包含中軌、上軌、下軌
"""
data['MA'] = data['close'].rolling(window=window).mean()
data['STD'] = data['close'].rolling(window=window).std()
data['Upper'] = data['MA'] + k * data['STD']
data['Lower'] = data['MA'] - k * data['STD']
return data[['MA', 'Upper', 'Lower']]
upper, middle, lower = talib.BBANDS(
df['close'].values,
timeperiod=20,
nbdevup=2,
nbdevdn=2,
matype=0
)
df['Upper'] = upper
df['MA'] = middle
df['Lower'] = lower
def generate_signals(df):
"""
生成交易信號
1 表示做多,-1 表示做空,0 表示無信號
"""
df['signal'] = 0
# 突破上軌做多
df.loc[(df['close'] > df['Upper']) & (df['close'].shift(1) <= df['Upper'].shift(1)), 'signal'] = 1
# 突破下軌做空
df.loc[(df['close'] < df['Lower']) & (df['close'].shift(1) >= df['Lower'].shift(1)), 'signal'] = -1
# 回歸中軌平倉
df.loc[
((df['close'] <= df['MA']) & (df['close'].shift(1) > df['MA'].shift(1))) |
((df['close'] >= df['MA']) & (df['close'].shift(1) < df['MA'].shift(1))),
'signal'
] = 0
return df
def manage_positions(df):
"""
管理持倉狀態
"""
df['position'] = 0 # 持倉方向:1多倉,-1空倉,0無倉
current_position = 0
for i in range(len(df)):
# 如果有信號且當前無持倉
if df.at[i, 'signal'] != 0 and current_position == 0:
current_position = df.at[i, 'signal']
# 如果出現平倉信號
elif df.at[i, 'signal'] == 0 and current_position != 0:
current_position = 0
df.at[i, 'position'] = current_position
return df
def calculate_returns(df):
"""
計算策略收益
"""
df['daily_return'] = df['close'].pct_change()
df['strategy_return'] = df['position'].shift(1) * df['daily_return']
df['cumulative_return'] = (1 + df['strategy_return']).cumprod()
return df
def analyze_performance(df):
"""
分析策略表現
"""
total_return = df['cumulative_return'].iloc[-1] - 1
annual_return = (1 + total_return) ** (252/len(df)) - 1
max_drawdown = (df['cumulative_return'].cummax() - df['cumulative_return']).max()
sharpe_ratio = df['strategy_return'].mean() / df['strategy_return'].std() * np.sqrt(252)
print(f"總收益率: {total_return*100:.2f}%")
print(f"年化收益率: {annual_return*100:.2f}%")
print(f"最大回撤: {max_drawdown*100:.2f}%")
print(f"夏普比率: {sharpe_ratio:.2f}")
plt.figure(figsize=(14, 7))
plt.plot(df['close'], label='Price', alpha=0.5)
plt.plot(df['MA'], label='Middle Band', linestyle='--')
plt.plot(df['Upper'], label='Upper Band', linestyle='--', color='red')
plt.plot(df['Lower'], label='Lower Band', linestyle='--', color='green')
plt.fill_between(df.index, df['Upper'], df['Lower'], color='grey', alpha=0.1)
plt.title('Bollinger Bands')
plt.legend()
plt.show()
plt.figure(figsize=(14, 7))
plt.plot(df['close'], label='Price', alpha=0.5)
# 標記買入信號
plt.scatter(
df.index[df['signal'] == 1],
df['close'][df['signal'] == 1],
marker='^', color='green', label='Buy Signal'
)
# 標記賣出信號
plt.scatter(
df.index[df['signal'] == -1],
df['close'][df['signal'] == -1],
marker='v', color='red', label='Sell Signal'
)
plt.title('Trading Signals')
plt.legend()
plt.show()
plt.figure(figsize=(14, 7))
plt.plot(df['cumulative_return'], label='Strategy')
plt.plot((1 + df['daily_return']).cumprod() - 1, label='Buy & Hold')
plt.title('Cumulative Returns')
plt.legend()
plt.show()
可以通過網格搜索尋找最優參數組合:
def optimize_parameters(df):
results = []
for window in range(10, 50, 5):
for k in [1.5, 2, 2.5]:
temp_df = calculate_bollinger_bands(df.copy(), window, k)
temp_df = generate_signals(temp_df)
temp_df = manage_positions(temp_df)
temp_df = calculate_returns(temp_df)
total_return = temp_df['cumulative_return'].iloc[-1] - 1
max_drawdown = (temp_df['cumulative_return'].cummax() - temp_df['cumulative_return']).max()
results.append({
'window': window,
'k': k,
'return': total_return,
'max_drawdown': max_drawdown
})
return pd.DataFrame(results)
可考慮加入以下改進: 1. 結合趨勢過濾器(如200日均線方向) 2. 加入成交量確認 3. 設置止損止盈機制
def add_risk_management(df, stop_loss=0.05, take_profit=0.1):
"""
添加止損止盈邏輯
"""
df['position'] = 0
current_position = 0
entry_price = 0
for i in range(len(df)):
# 開倉邏輯
if df.at[i, 'signal'] != 0 and current_position == 0:
current_position = df.at[i, 'signal']
entry_price = df.at[i, 'close']
# 止損止盈邏輯
elif current_position != 0:
pct_change = (df.at[i, 'close'] - entry_price) / entry_price
if (current_position == 1 and (pct_change <= -stop_loss or pct_change >= take_profit)) or \
(current_position == -1 and (pct_change >= stop_loss or pct_change <= -take_profit)):
current_position = 0
# 中軌平倉邏輯
elif df.at[i, 'signal'] == 0 and current_position != 0:
current_position = 0
df.at[i, 'position'] = current_position
return df
# 完整策略實現
def run_bollinger_strategy(data, window=20, k=2, stop_loss=None, take_profit=None):
# 計算布林帶
data = calculate_bollinger_bands(data, window, k)
# 生成信號
data = generate_signals(data)
# 添加風險管理
if stop_loss and take_profit:
data = add_risk_management(data, stop_loss, take_profit)
else:
data = manage_positions(data)
# 計算收益
data = calculate_returns(data)
return data
# 運行策略
result = run_bollinger_strategy(df.copy(), window=20, k=2, stop_loss=0.03, take_profit=0.06)
analyze_performance(result)
本文實現了一個基于布林帶突破的商品期貨交易策略,主要特點包括: 1. 使用Python實現了布林帶指標計算 2. 構建了完整的信號生成和持倉管理系統 3. 加入了基礎的回測和績效評估功能 4. 提出了策略優化和風險控制的改進方向
實際應用中需要注意: - 歷史回測不能完全預測未來表現 - 需考慮交易成本和滑點影響 - 建議在模擬盤充分測試后再投入實盤
通過不斷優化參數和加入更多過濾條件,可以進一步提高策略的穩定性和盈利能力。 “`
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。