金桔
金币
威望
贡献
回帖0
精华
在线时间 小时
|
研究时间序列投资有两种思路,一种是用模型给出未来价格的随机分布情况,另一种是用模型直接给出买卖点。这篇文章主要介绍后一种思路中的关键步骤,买卖点确认问题。
买卖点的作用
买卖点的确认相当于是为以后的拟合算法制作标准答案。
买卖点确认问题
可能有些人认为这不是个问题。直接用两天的数据比对,如果涨就买,如果跌就卖。但这样的买卖点做出来之后会表现得非常随机,以至于很难去做一个模型去预测这样几乎没有规律的买卖点,或者说即使能预测也会很麻烦,要结合很多方面的数据。而只要减少交易次数,有些指标就可以给出一点趋势的痕迹。从而达到“顺势而为”的目的。但在此之前我们需要用算法来解决上述提到的问题。
问题:
有一个已知的时间序列,问如何交易才能使得固定交易次数的情况下,获利最多。
为什么一到要取最优解,看着能赚钱就好了不是么?
在制作模型阶段,任何东西都可能导致整个模型意外,而买卖点就是程序需要学习的答案,如果这一步就没有达到最优解,那么接下来做模型只会错得更离谱。买卖点的确认首先是确认上限在哪,在真正预测的时候是没法达到上限的,可能能有上限的10%就已经很不错了。这时候如果没有达到最优解,胡乱的浪费交易次数会对预测造成严重干扰。
试想一下三年内,总共交易150次,结果按照凭感觉的做出的买卖点只能略微跑赢大盘,那么模型学习阶段就会把一个不完美的买卖点当做标准答案,学出来的结果大概率跑不赢大盘。
用代码定义一下:
def getOptimalBS(ys,tradeNumber)
"""
ys: 时间序列 长度为N
tradeNumber: 交易次数
return 买入为1 卖出为0,长度为N的序列
"""近似算法
def getWaitAllGreedyOPT(ys,prd=5):
qs = np.zeros(len(ys))
pre_q = 0
for i in range(len(ys[:-prd])):
#last chunck is -prd-1,-prd,,-prd+1,-prd+2 ... -prd+(prd-1)=-1 total N
# num of chunck = prd+1
sub = ys[i:i+prd+1]
# chunck = i+0, i+1,..., i+(prd)
# num of chunk = prd+1 including the current idx
logSub = np.log(sub)
log_gain_loss = logSub[1:]-logSub[0]
if pre_q == 1:
if np.all(log_gain_loss<0):
qs = -1
else:
qs = 1
elif pre_q == -1:
if np.all(log_gain_loss>0):
qs = 1
else:
qs= -1
else:
if np.all(log_gain_loss>0):
qs = 1
else:
qs = -1
pre_q = qs
return qs
def getWaitGreedyOPT(ys,prd=5):
qs = np.zeros(len(ys))
pre_q = 0
for i in range(len(ys[:-prd])):
#last chunck is -prd-1,-prd,,-prd+1,-prd+2 ... -prd+(prd-1)=-1 total N
# num of chunck = prd+1
sub = ys[i:i+prd+1]
# chunck = i+0, i+1,..., i+(prd)
# num of chunk = prd+1 including the current idx
logSub = np.log(sub)
log_gain_loss = logSub[1:]-logSub[:-1]
head,tail = logSub[0],logSub[-1]
if pre_q == 1:
if tail<head and log_gain_loss[0]<0:
qs = -1
else:
qs = 1
elif pre_q == -1:
if tail>head and log_gain_loss[0]>0:
qs = 1
else:
qs= -1
else:
if log_gain_loss[0]>0:
qs = 1
else:
qs = -1
pre_q = qs
return qs
def getGreedyDailyOPT(ys,prd=5):
qs = np.zeros(len(ys))
for i in range(len(ys[:-prd])):
sub = ys[i:i+prd+1]
logSub = np.log(sub)
log_gain_loss = logSub[1:]-logSub[:-1]
if log_gain_loss[0]>0:
qs = 1
else:
qs = -1
return qs
def getLongWaitOPT(ys,prd=5):
qs = np.zeros(len(ys))
for i in range(len(ys[:-prd])):
sub = ys[i:i+prd+1]
head,tail = sub[0],sub[-1]
if tail>head:
qs = 1
else:
qs = -1
return qs
结果
Code Algo Default Gain Trade Gain #Trade #Data Point
0 #GBTC getGreedyDailyOPT-D1 239.7% 1300300471.0% 380 756
1 #GBTC getWaitAllGreedyOPT-D1 239.7% 1300300471.0% 380 756
2 #GBTC getWaitGreedyOPT-D5 239.7% 9376123.5% 134 756
3 #GBTC getWaitAllGreedyOPT-D5 239.7% 13366867.9% 106 756
4 #GBTC getLongWaitOPT-D5 239.7% 264767.9% 148 756
5
6 #GBTC getGreedyDailyOPT-D1 239.7% 1300300471.0% 380 756
7 #GBTC getWaitAllGreedyOPT-D1 239.7% 1300300471.0% 380 756
8 #GBTC getWaitGreedyOPT-D10 239.7% 558461.3% 92 756
9 #GBTC getWaitAllGreedyOPT-D10 239.7% 325524.4% 42 756
10 #GBTC getLongWaitOPT-D10 239.7% 42862.2% 98 756
11
12 #GBTC getGreedyDailyOPT-D1 239.7% 1300300471.0% 380 756
13 #GBTC getWaitAllGreedyOPT-D1 239.7% 1300300471.0% 380 756
14 #GBTC getWaitGreedyOPT-D20 239.7% 117150.5% 54 756
15 #GBTC getWaitAllGreedyOPT-D20 239.7% 100793.4% 24 756
16 #GBTC getLongWaitOPT-D20 239.7% 8034.3% 56 756
17
18 #QQQ getGreedyDailyOPT-D1 192.5% 7238.2% 396 756
19 #QQQ getWaitAllGreedyOPT-D1 192.5% 7238.2% 396 756
20 #QQQ getWaitGreedyOPT-D5 192.5% 2015.2% 132 756
21 #QQQ getWaitAllGreedyOPT-D5 192.5% 1819.2% 88 756
22 #QQQ getLongWaitOPT-D5 192.5% 895.6% 148 756
23
24 #QQQ getGreedyDailyOPT-D1 192.5% 7238.2% 396 756
25 #QQQ getWaitAllGreedyOPT-D1 192.5% 7238.2% 396 756
26 #QQQ getWaitGreedyOPT-D10 192.5% 982.6% 78 756
27 #QQQ getWaitAllGreedyOPT-D10 192.5% 877.9% 36 756
28 #QQQ getLongWaitOPT-D10 192.5% 603.1% 88 756
29
30 #QQQ getGreedyDailyOPT-D1 192.5% 7238.2% 396 756
31 #QQQ getWaitAllGreedyOPT-D1 192.5% 7238.2% 396 756
32 #QQQ getWaitGreedyOPT-D20 192.5% 473.6% 48 756
33 #QQQ getWaitAllGreedyOPT-D20 192.5% 585.0% 18 756
34 #QQQ getLongWaitOPT-D20 192.5% 335.2% 50 756
35
36 #DIA getGreedyDailyOPT-D1 143.4% 1697.4% 376 756
37 #DIA getWaitAllGreedyOPT-D1 143.4% 1697.4% 372 756
38 #DIA getWaitGreedyOPT-D5 143.4% 642.4% 120 756
39 #DIA getWaitAllGreedyOPT-D5 143.4% 751.1% 92 756
40 #DIA getLongWaitOPT-D5 143.4% 360.4% 134 756
41
42 #DIA getGreedyDailyOPT-D1 143.4% 1697.4% 376 756
43 #DIA getWaitAllGreedyOPT-D1 143.4% 1697.4% 372 756
44 #DIA getWaitGreedyOPT-D10 143.4% 466.6% 78 756
45 #DIA getWaitAllGreedyOPT-D10 143.4% 476.6% 38 756
46 #DIA getLongWaitOPT-D10 143.4% 284.0% 86 756
47
48 #DIA getGreedyDailyOPT-D1 143.4% 1697.4% 376 756
49 #DIA getWaitAllGreedyOPT-D1 143.4% 1697.4% 372 756
50 #DIA getWaitGreedyOPT-D20 143.4% 288.1% 48 756
51 #DIA getWaitAllGreedyOPT-D20 143.4% 329.5% 18 756
52 #DIA getLongWaitOPT-D20 143.4% 215.5% 58 756
53
54 #510300.SS getGreedyDailyOPT-D1 138.4% 5160.6% 376 756
55 #510300.SS getWaitAllGreedyOPT-D1 138.4% 5160.6% 372 756
56 #510300.SS getWaitGreedyOPT-D5 138.4% 1850.3% 138 756
57 #510300.SS getWaitAllGreedyOPT-D5 138.4% 1872.1% 102 756
58 #510300.SS getLongWaitOPT-D5 138.4% 787.2% 154 756
59
60 #510300.SS getGreedyDailyOPT-D1 138.4% 5160.6% 376 756
61 #510300.SS getWaitAllGreedyOPT-D1 138.4% 5160.6% 372 756
62 #510300.SS getWaitGreedyOPT-D10 138.4% 922.1% 106 756
63 #510300.SS getWaitAllGreedyOPT-D10 138.4% 874.0% 50 756
64 #510300.SS getLongWaitOPT-D10 138.4% 484.4% 122 756
65
66 #510300.SS getGreedyDailyOPT-D1 138.4% 5160.6% 376 756
67 #510300.SS getWaitAllGreedyOPT-D1 138.4% 5160.6% 372 756
68 #510300.SS getWaitGreedyOPT-D20 138.4% 555.5% 70 756
69 #510300.SS getWaitAllGreedyOPT-D20 138.4% 527.6% 28 756
70 #510300.SS getLongWaitOPT-D20 138.4% 318.0% 84 756
getGreedyDailyOPT 就是时间序列在完全已知的情况下的极限收益率
getLongWaitOPT 如果5天(包括当天收盘价)会涨就买,跌就卖。
getWaitGreedyOPT 可以理解为一定程度的延迟,等到真的出现拐点的时候再交易,而不是在之前还能涨,或者还没跌完的时候交易。这种交易方法可以比getLongWaitOPT 使用更少的交易次数,赚更多的收益。
getWaitAllGreedyOPT 是在getWaitGreedyOPT 上进一步改进,只有当local min和local max出现的时候才开始交易。其余时间都保持原有的状态,收益和getWaitGreedyOPT相比收益可能低,也可能高,但可以大幅度减少交易次数。
getWaitAllGreedyOPT-D1 可以看做是在getGreedyDailyOPT经常时间上做的一点点优化。
注:如果有人做出来这个最优买卖点算法请告诉我,不胜感激。 |
|