注意到在上一篇文章的代码实现中,我们设置了一些参数,这些参数也影响了我们实际交易中信号触发的条件和周期。为此,设计了网格调优的程序,寻找能产生最大收益或者控制最大回撤的对应参数。我们希望年均回报率能够大于15%,而希望最大回撤能控制在-20%以内。
首先导入需要的module,并读取所需的外汇数据:
import datetime as dt
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['Kaiti']
plt.rcParams['axes.unicode_minus']=False
import mplfinance as mpf
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings("ignore")
df1 = pd.read_csv('eurusd_daily.csv', parse_dates=["Date"], index_col="Date")
df1.drop(['Change'], axis=1, inplace=True)
将之前写的海龟交易法回测程序主体写成一个自定义函数
def turtle_optimization(n1=30,n2=15,atr_parameter=30,start_date='1990-01-01',end_date='2020-12-31',df=df1):
df['DonHigh_n1'] = df['High'].rolling(n1).max().shift(1)
df['DonLow_n1'] = df['Low'].rolling(n1).min().shift(1)
df['DonHigh_n2'] = df['High'].rolling(n2).max().shift(1)
df['DonLow_n2'] = df['Low'].rolling(n2).min().shift(1)
df['H-L'] = abs(df['High'] - df['Low'])
df['H-PC'] = abs(df['High'] - df['Close'].shift(1))
df['L-PC'] = abs(df['Low'] - df['Close'].shift(1))
df['TR'] = df[['H-L', 'H-PC', 'L-PC']].max(axis=1, skipna=False)
df['ATR'] = df['TR'].rolling(atr_parameter).mean()
df.drop(['H-L','H-PC','L-PC','TR'], axis=1, inplace=True)
df.dropna(inplace=True)
st = dt.datetime.strptime(start_date, '%Y-%m-%d')
en = dt.datetime.strptime(end_date, '%Y-%m-%d')
df = df[st:en]
# 仓位和量价的初始化
position = 0
df['position'] = np.nan
last_price = 0
df['profit'] = np.nan
volume = 0
def DCn1upcross(i):
if df['High'][i] > df['DonHigh_n1'][i] and df['High'][i-1] <= df['DonHigh_n1'][i-1]:
return True
else:
return False
def DCn1downcross(i):
if df['Low'][i] < df['DonLow_n1'][i] and df['Low'][i-1] >= df['DonLow_n1'][i-1]:
return True
else:
return False
def DCn2upcross(i):
if df['High'][i] > df['DonHigh_n2'][i] and df['High'][i-1] <= df['DonHigh_n2'][i-1]:
return True
else:
return False
def DCn2downcross(i):
if df['Low'][i] < df['DonLow_n2'][i] and df['Low'][i-1] >= df['DonLow_n2'][i-1]:
return True
else:
return False
# 股票仓位:0, 1, -1分别代表不持仓,持多头仓位和持空头仓位
for i in range(len(df)-1):
if position == 0:
if DCn1upcross(i):
position = 1
last_price = df['Close'][i] #入场价格等于当天收盘价,未考虑滑点
volume = df['ATR'][i]/0.0001*10 #0.0001为外汇的最小基点
if DCn1downcross(i):
position = -1
last_price = df['Close'][i] #入场价格等于当天收盘价,未考虑滑点
volume = df['ATR'][i]/0.0001*10 #0.0001为外汇的最小基点
if position == 1:
if DCn2downcross(i):
position = 0
df['position'][i] = 0 #将多头全部平掉
df['profit'][i] = (df['Close'][i]-last_price)/0.0001*volume
if position == -1:
if DCn2upcross(i):
position = 0
df['position'][i] = 0 #将空头全部平掉
df['profit'][i] = (last_price-df['Close'][i])/0.0001*volume
if i == len(df)-2:
if position == 1:
position = 0
df['position'][i] = 0 #将多头全部平掉
df['profit'][i] = (df['Close'][i]-last_price)/0.0001*volume
if position == -1:
position = 0
df['position'][i] = 0 #将空头全部平掉
df['profit'][i] = (last_price-df['Close'][i])/0.0001*volume
# 结果计算
# df['profit'].dropna()
# df['profit'].dropna().sum()
account = 1000000 #初始账户的金额(计算回报率用)
df['return'] = df['profit']/account #每次操作的回报率
df['return'].dropna()
sum = df['return'].sum()
# print ("总回报率倍数:", round(sum,2))
return round(sum,2)
调用海龟交易法程序,并设置相应的参数为n1=40,n2=20,atr_parameter=30
turtle_optimization(n1=40, n2=20, atr_parameter=30)
此时总体回报率达到:
7.27 (对应727%)
通过for循环,让不同的n1(取从20到40的所有整数)和n2(取从20到70的所有证书)自由组合,计算所有组合情况下的最大回报率。
n1=np.array(range(20,41,1))
n2=np.array(range(20,71,1))
best_return = 0
best_n1 = 0
best_n2 = 0
from tqdm import *
for num1 in tqdm(n1):
for num2 in n2:
result = turtle_optimization(num1, num2)
if result > best_return:
best_return = result
best_n1 = num1
best_n2 = num2
best_return, best_n1, best_n2
得到最大回报率所对应的n1和n2的值分别为:
20, 21
此时总体回报率达到
11.64 (1,164%)
同理,还可以针对n1, n2及atr_parameter等参数一起进行网格调参,也还可以针对最大回撤率进行求解最优参数等。