看着別人炒股掙錢,心里總是心癢癢,但是每次一入市,總能被當韭菜收割,沉不住氣。近期看了《海龜交易法則》,里面提到一些說法,覺得有點意思,所以拿歷史數據試一試,探探究竟,不作為投資建議,僅供娛樂。
拋出書里的幾個說法: 1、投資可以標准化,但是每幾個人能堅持; 2、找到一個期望值為正的操作系統,不如有55%的概率是掙錢的,那么只要不斷的重復,最終總可以贏錢,除非你是45%*45%...*45%的倒霉蛋; 3、風險空值,逐步試行; 4、簡單就可以了,復雜的系統反而會出現過度擬合;
使用python進行數據收集和處理,最后進行結果分析和展示。使用到pandas庫、金融數據庫使用了akshare(免費,tushare也可以,但是要有積分),但是
akshare收集到的數據,與不同平台的進行比較(wind,東方財富)有微小偏差,暫忽略不計。
akshare:https://www.akshare.xyz/zh_CN/latest/data/stock/stock.html#id5
***本次回測操作方法為趨勢交易,采用60日均線上穿250日均線時買入(認為開啟往上漲的趨勢),下穿時賣出(認為上漲結束開始下跌)
使用當前A股從2000年1月1日到2020年11月26日數據進行測試。
以當前數據的結論是:截止到2020年11月26日,包含持有的收益是(6000倍),但是需要操作的資金量大,操作股票數量較多,且存在連續虧損的年份,雖然總體為
正收益,但是執行起來信心難以保障。
1、獲取機構名單,這個通過wind查詢了機構的名單;
2、獲取數據,通過akshare庫獲取每只股票從2000年開始,每一天的數據,采用后復權。
后復權:保證歷史價格不變,在每次股票權益事件發生后,調整當前的股票價格。 后復權價格和真實股票價格可能差別較大,不適合用來看盤。 其優點在於,可以被看作投資者的長期財富增長曲線,反映投資者的真實收益率情況。
%%time # 讀取全部A股數據 for i, row in org.iterrows(): code = row['akcode'] t1 = row['上市日期'] if t1 < datetime.datetime(2000,1,1): t1 = datetime.datetime(2000,1,1) t2 = datetime.datetime.now() print(str(i),code,'開始讀取。') berr = True try: #調用API接口獲取數據 df = ak.stock_zh_a_daily(symbol=code, start_date=t1.strftime("%Y%m%d"), end_date=t2.strftime("%Y%m%d"), adjust="hfq") except: print(code + '讀取' + t1.strftime("%Y-%m-%d") + ' -- ' + t2.strftime("%Y-%m-%d") + '有問題。') berr = False l = [] # 合並 if berr: df = df.reset_index() # 修改名字 df.columns = [ x.upper() for x in df.columns] df.rename(columns={"DATE": "index"},inplace=True) df = df[df['OPEN'].notnull()] # 通過rolling滾動計算均線和BOLL通道 df['MA_5'] = df['CLOSE'].rolling(window=5).mean() df['MA_10'] = df['CLOSE'].rolling(window=10).mean() df['MA_20'] = df['CLOSE'].rolling(window=20).mean() df['MA_30'] = df['CLOSE'].rolling(window=30).mean() df['MA_60'] = df['CLOSE'].rolling(window=60).mean() df['MA_250'] = df['CLOSE'].rolling(window=250).mean() df['BOLL_STD'] = df['CLOSE'].rolling(window=250).std() df['BOLL_UPPER'] = df['MA_250'] + 2 * df['BOLL_STD'] df['BOLL_LOWER'] = df['MA_250'] - 2 * df['BOLL_STD'] with pd.ExcelWriter(r'../data/huice/aklishi/' + code + '.xlsx') as writer: df.to_excel(writer,index=False,sheet_name = 'Sheet1')
3、開始進行回測;
# 判斷買賣結點 # 采用短線均線上穿長線均線為買點 # 采用短線均線下穿長線均線為賣點 def is_dbljx(data,i,mode = 'buy',j1='MA_60',j2='MA_250'): if i < 250: return False if mode == 'buy': if (data.loc[i,j1] > data.loc[i,j2]) & (data.loc[i-1,j1] < data.loc[i-1,j2]): return True else: if (data.loc[i,j1] < data.loc[i,j2]) & (data.loc[i-1,j1] > data.loc[i-1,j2]): return True return False # data總數據,l操作記錄列表(買、賣形成一條記錄) # 計算出每一次持有股票的盈利金額、盈利幅度、持有天數、期間最高收益、區間最低收益 def huizong_one(data,l): # 輸出結果 dfout = pd.DataFrame(l, columns=['證券代碼','買入索引','賣出索引', '買入日期','賣出日期', '買入價格', '賣出價格','狀態']) dfout = dfout.reindex(columns=['證券代碼', '買入索引','賣出索引', '買入日期','賣出日期', '買入價格', '賣出價格','狀態','期間最高收益','期間最低收益','盈利金額','盈利幅度','持有天數']) # ,'盈利金額','盈利幅度','持有天數' for i, row in dfout.iterrows(): dfout.loc[i,'盈利金額'] = dfout.loc[i,'賣出價格'] - dfout.loc[i,'買入價格'] dfout.loc[i,'盈利幅度'] = (dfout.loc[i,'賣出價格'] - dfout.loc[i,'買入價格']) / dfout.loc[i,'買入價格'] * 100 dfout.loc[i,'持有天數'] = dfout.loc[i,'賣出日期'] - dfout.loc[i,'買入日期'] m = data.loc[dfout.loc[i,'買入索引']:dfout.loc[i,'賣出索引'],'CLOSE'].max() if m < dfout.loc[i,'賣出價格']: m = dfout.loc[i,'賣出價格'] dfout.loc[i,'期間最高收益'] = (m - dfout.loc[i,'買入價格'])/dfout.loc[i,'買入價格'] * 100 m = data.loc[dfout.loc[i,'買入索引']:dfout.loc[i,'賣出索引'],'CLOSE'].min() if m > dfout.loc[i,'賣出價格']: m = dfout.loc[i,'賣出價格'] dfout.loc[i,'期間最低收益']= (m - dfout.loc[i,'買入價格'])/dfout.loc[i,'買入價格'] * 100 return dfout
回測主體:
%%time # 遍歷回測所有采集的股票數據 folder_name = r'../data/huice/aklishi/' file_list = os.listdir(folder_name) ldf = [] if len(file_list) > 0 : # 遍歷文件夾下所有文件 ldf = [] for f in range(len(file_list)): data = pd.read_excel(folder_name + str(file_list[f]),dtype=object) data['bs'] = '' code = str(file_list[f])[:-5] l = [] buy_index = 0 # 因為比較的是60日線和250日線,所以從第251個開始 for i in range(250,len(data)): # 判斷買賣信號 if is_dbljx(data,i,'buy'): # 記錄買點 buy_index = i data.loc[i,'bs'] = 'b' # 賣出信號 elif (buy_index != 0) & is_dbljx(data,i,'sell'): # 證券代碼 買入索引 賣出索引 買入日期 賣出日期 買入價格 賣出價格 # 記錄下買賣點,清除買點 l.append([code,buy_index,i,data.loc[buy_index,'index'],data.loc[i,'index'],data.loc[buy_index,'CLOSE'],data.loc[i,'CLOSE'],'終止']) buy_index = 0 data.loc[i,'bs'] = 's' # 結束以后保存結果 with pd.ExcelWriter(folder_name + str(file_list[f])) as writer: data.to_excel(writer,index=False,sheet_name = 'Sheet1') # 匯總單次結果 if buy_index != 0: # 記錄一個當前 l.append([code,buy_index,i-1,data.loc[buy_index,'index'],data.loc[i-1,'index'],data.loc[buy_index,'CLOSE'],data.loc[i-1,'CLOSE'],'持有']) ldf.append(huizong_one(data,l)) # 存儲每只股票的操作結果 # 最后匯總輸出 dfout = pd.concat(ldf,ignore_index=True) with pd.ExcelWriter(r'../data/huice/回測結果2.xlsx') as writer: dfout.to_excel(writer,index=False,sheet_name = 'Sheet1',float_format="%.2f")
最終形成的數據:
4、結果分析
4.1 總體情況來看
從2000-01-01 -- 2020-11-26 以來,按照收盤價,60日均線上穿250日均線時進行買入,60日均線下穿250日均線時進行賣出,共進行操作21948次(每一次都買入一樣的價錢),平均持有天數是293天,虧損次數13331次,盈利次數8568次,只有大概4成的操作是盈利的,但是盈利幅度總和達到605232.1%(6052倍),總共是盈利的。
最大一次虧損達到-68.5%,相當於1萬元,虧損剩下3000來,最大一次盈利是24倍!
4.2 從過程來看
持有期間,最高一次收益是52倍,最低持有收益是-72.22%,意味着你某次操作得承受虧損72%,持有天數達223天,最大一次利潤回吐是84.15%,經歷了從盈利3倍到虧損27%的痛。
4.3 分時間操作來看
買入來看,在2007年僅操作了84次,在2019年3401次。假設每次操作都投入1萬元,那么- -||在不考慮存量股票的情況下,你需要3401萬資金,貧窮限制了我的操作。
賣出來看,最多賣出時在2019年2242次(2020年賣出1671次,還在持有的有(2515,前面的計算是計算到截至11月26日的收益),最少賣出時間是在2009年。
分年度收益來看,20年來,僅有11年是正收益,在2008年的時候,產生了3052倍收益,在2019年時造成了321倍的虧損....這相當於,每次投入1萬塊,在2019年會虧個幾百萬。從這個系統運行起來看,2001年-2006年經歷了長達5年的虧損,正常人相比都會懷疑自己的系統不行的了。難!
分個股收益來看。 總操作股票3570個,其中虧損的有915個,越大概四分之一的股票會虧損,這么一看,選擇單個股票執行這個策略有25%的概率會失敗,其中失敗最慘的一次是虧損1.39倍。盈利來說有2655個,總收益是6342倍,最小的一次收益是30%,極端情況下,我選兩次股票進行操作,不排除出現(-1.39,0.30)的組合,最終虧損一倍。下一步因對標記了的虧損股票進行一次數據挖掘分析,得出虧損的股票都有些什么性質,進而進行排除。
5、結論
從當前的操作來看這一次回測,第一,雖然能掙錢,資金量需要有點多;
第二,操作的股票太多,2020年持有2515只股票,等價於操作了股票市場一半多的股票。
第三,根據交易者效應,你發現能夠賺錢的策略被別人知道以后開始跟風就會變得不賺錢,然而系統的正確性又需要時間來驗證,如果出現了交易者效應或其他因素導致系統連續虧錢如2001年 -- 2006年,那么就會導致對系統變得沒有信心,最終就會錯過2007年、2008年以致於后面豐收的年份。
第四,需要進行分散投資;
總體來說,有點跳大神的感覺,以為自己在某個時間段合適的理論,結果只是巧合?三體轉。
回頭再考慮結合一下,大盤的情況進行回測看看。