ETF定投数据分析5——蒙特卡洛算法

接下来就用蒙特卡洛算法分析一下数据吧。老规矩,先新建一个名为MonteCarlo的分支,新建一个名为MonteCarlo.py的文件。先看一下我的数据,平均每7个交易日交易一次,手续费率0.0003(万分之三,不足0.1元收0.1元)。购买300etf和纳指etf两个股票,金额平分。即交易28次,每次交易金额1000元,剩下的,并到下次交易。以上就是模拟的假设。
接下来就是进行交易模拟的函数,比较长,主要是一些细节的计算。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
'''执行一次交易模拟
输入的参数
cost 总交易成本
time 交易周期的天数
freq 交易频率,几天交易一次
df_300, df_nas,分别为两个定投的etf的实盘成交数据
返回值为一个DataFrame,包含每个交易日的成本,收益,收益率等数据
'''
def work(cost, time, freq, df_300, df_nad):
#计算交易次数
tradetimes = int(time/freq)
print(tradetimes)
#计算每次交易的金额
money = cost/tradetimes
print(money)
#手续费比率
fee_rate = 0.0003
#把每次交易金额均分为两部分,分别买两个etf,如果钱不够交易,留到下次
money_300 = money/2.0
money_nas = money/2.0
#开始模拟前定义相关变量
cost = [] #投入的总成本
cost3 = [] #买300etf的成本
costN = [] #买纳指etf的成本
m3 = 0.0 #买300etf的钱
mN = 0.0 #买纳指etf的钱
fee = [] #手续费
V3 = [] #300etf股票数量
VN = [] #纳指etf股票数量
Total3 = [] #300etf的当前市值
TotalN = [] #纳指etf的当前市值
Total = [] #当前总市值
Income3 = [] #300etf的收益
IncomeN = [] #nasetf的收益
Income = [] #总收益
Rate3 = [] #300etf收益率
RateN = [] #nasetf收益率
Rate = [] #总收益率
#每次交易剩下的钱
money_300_rem = 0.0
money_nas_rem = 0.0

#开始模拟
j = 0
for i in range(time):
if j == 0: #交易
#计算可以买的股票数量
num_300 = int(money_300/df_300["close"][i]/100)*100
num_nas = int(money_nas/df_nas["close"][i]/100)*100
if i == 0:
V3.append(num_300)
VN.append(num_nas)
else:
V3.append(V3[i-1] + num_300)
VN.append(VN[i-1]+ num_nas)
#计算购入成本
m3 = num_300*df_300["close"][i]
fee_300 = m3*fee_rate
if fee_300 < 0.1:
fee_300 = 0.1
money_300_rem = money_300 - m3 - fee_300
money_300 += money_300_rem
mN = num_nas*df_nas["close"][i]
fee_nas = mN*fee_rate
if fee_nas < 0.1:
fee_nas = 0.1
fee.append(fee_300 + fee_nas)
money_nas_rem = money_nas - mN - fee_nas
money_nas += money_nas_rem

#计算总成本
total_cost = m3+fee_300+mN+fee_nas
if i == 0:
cost3.append(m3+fee_300)
costN.append(mN+fee_nas)
cost.append(cost3[i] + costN[i])
else:
cost3.append(cost3[i-1] + m3 + fee_300)
costN.append(costN[i-1] + mN + fee_nas)
cost.append(cost[i-1] + cost3[i] + costN[i])
#其它数据无论是否交易都要算,放最后
else: #不交易
fee.append(0.0)
cost.append(cost[i-1])
cost3.append(cost3[i-1])
costN.append(costN[i-1])
V3.append(V3[i-1])
VN.append(VN[i-1])
#无论是否交易都要算的持仓市值,收益,收益率
j += 1
if j >= freq:
j = 0
Total3.append(V3[i]*df_300["close"][i])
TotalN.append(VN[i]*df_nas["close"][i])
Total.append(Total3[i] + TotalN[i])
Income3.append(Total3[i] - cost3[i])
IncomeN.append(TotalN[i] - costN[i])
Income.append(Income3[i] + IncomeN[i])
Rate3.append(Income3[i]/cost3[i])
RateN.append(IncomeN[i]/costN[i])
Rate.append(Income[i]/cost[i])

data = pd.DataFrame(
{
"成本":cost,
"手续费":fee,
"市值":Total,
"收益":Income,
"收益率":Rate
}
)
return data

测试一下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#进行模拟
#先获取成本,交易周期等信息
cost = df_etf["成本"].values[-1]
print(cost)
time = len(df_etf)
#进行交易模拟
data = work(cost, time, 10, df_300, df_nas)
print(data.head())
testdata = pd.DataFrame(
{
"数据":data["收益率"].values
}
)
result = index.index(testdata, df_base, 0.03)
print(result)


OK,测试成功。以后还可以进一步完善,比如设定止盈止损规则等。先从最简单的来吧,改变交易频率看看,即从每日进行交易到每30个交易日进行一次交易,看看数据有何不同。
建一个函数进行模拟

1
2
3
4
5
6
#按不同交易频率进行交易
def Run(cost, time, df_300, df_nas):
data = []
for freq in range(1, 31):
data.append(work(cost, time, freq, df_300, df_nas))
return data

然后调用

1
2
3
4
5
6
7
8
9
10
11
12
13
#测试成功,现在模拟不同交易频率对结果的影响
testresult = Run(cost, time, df_300, df_nas)
testindex = [] #保存测试结果的回测指标
for res in testresult:
print(res.head())
test = pd.DataFrame(
{
"数据":res["收益率"].values
}
)
testindex.append(index.index(test, df_base, 0.03))
for test in testindex:
print(test.head())


再画图看一下,先比较一下年化收益率。

1
2
3
4
5
6
7
8
AR =[]
for test in testindex:
print(test.head())
AR.append(test["年化收益率"])
#数据可视化
fig = plt.figure()
plt.plot(AR)
fig.savefig("montecarlo_ar.png")


随着交易频率的下降,年化收益率也下降?再看看最大回撤

随着交易频率的下降,最大回撤值上升。
阿尔法值

夏普系数

从中可以总结出各种规律,貌似交易频率越高越好?但第一收益率全是负的而不是正的,第二交易天数仅200余天,好像有点少。不过这算是基本的模拟方法,更进一步的探索,留待下次吧。
明天就是春节了,提前祝大家猪年吉祥!明年见!
我发文章的三个地方(对,多了一个,计算机方面的文章可能会发CSDN的博客上。所有的文章都会发在github个人博客上),欢迎大家在朋友圈等地方分享,欢迎点“好看”。谢谢。
我的个人博客地址:https://zwdnet.github.io
我的CSDN博客地址:https://blog.csdn.net/zwdnet
我的微信个人订阅号:赵瑜敏的口腔医学学习园地

欢迎打赏!感谢支持!