python 海龜交易法則 股票回測-雙均線規則(一)


看着別人炒股掙錢,心里總是心癢癢,但是每次一入市,總能被當韭菜收割,沉不住氣。近期看了《海龜交易法則》,里面提到一些說法,覺得有點意思,所以拿歷史數據試一試,探探究竟,不作為投資建議,僅供娛樂。

拋出書里的幾個說法:
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年以致於后面豐收的年份。

   第四,需要進行分散投資;

   總體來說,有點跳大神的感覺,以為自己在某個時間段合適的理論,結果只是巧合?三體轉。

   回頭再考慮結合一下,大盤的情況進行回測看看。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM