2021年3月15日 星期一

[Python][量化狼]為何交易總是從天選之人變地獄倒霉鬼

 


上一次談到 蒙地卡羅模擬小樣本內隨機性的問題

蒙地卡羅模擬下的交易天選之人

隨後來了廣大的迴響,所以今天就來細看一下數據分析


策略原始設定是 勝率31% 賺賠比2.7 ,每次用資金的10%去下注,實驗結果是
即便是期望值大於0的策略
在小樣本內,還是有接近40%會賠錢



依照分類的數據,進行分組並且統計,發現:

1.所有樣本的 MaxDD  都太高了
所以代表預設的10%資金控管是有問題的,這往後有機會再討論

所有樣本的初始本金都是100萬
1000萬以上的天選組就不多說,因為就是運氣超好勝率高,所以爆賺
0~10萬 地獄倒霉鬼組慘到不行  只剩下15%的勝率 所以幾乎把錢賠光
10~50萬 (29%勝率)與 50~100萬(30%勝率) 讓我感到比較意外,因為依照理論來計算期望值
即便在29% 與 30%勝率的期望值下 理論上來說是可以獲利的

10~50   這組期望值     29%*2.7+71%*-1=0.083 >0
50~100 這組期望值     30%*2.7+70%*-1=0.11   >0
策略原始設定期望值  31%*2.7+69%*-1=0.147

10~50 與 50~100這兩組實驗起來是賠錢的,這裡面代表了一件事情
2.期望值不夠高的策略,在小樣本中賠錢機率很高

這跟量化交易一樣,幾乎所有策略在現實狀況中都會開始"退化"
所謂的"退化"就是 策略的勝率降低 MaxDD增加 
這也導致:為什麼回測的時候策略的時候都很棒 都可以賺錢
可是上架後,就開始賠錢了因為策略開始產生"退化"
勝率一降低,就從天選之人變成地獄倒楣鬼
只會變成上架後賠錢那40%  
因為跟蒙地卡羅模擬一樣,策略上架不退化就不錯了
難道你還期望勝率會比回測高,可以往天選之人那一邊去?
所以現實中,很難變成天選之人

前幾天有po一篇開槓桿的資金效率問題,談的是很類似的概念
Sharp Ratio 在1.5倍左右,最佳槓桿倍數大概是6倍左右

10%的風險控管代表說槓桿開太大,損益不夠穩定,
所以導致很容易陣亡

回到一個重點
策略不夠好,風險要控制得很嚴格,不然在現實狀況中
小心了,弄不好,你就會成為地獄倒霉鬼!



隨後附上 計算MaxDD 跟 計算連續勝利次數的程式碼
有興趣研究Python 的可以結合上一次的蒙地卡羅分析研究一下
----------------------------python 程式碼----------------------
import pandas as pd
import numpy as np
import random
import matplotlib.pyplot as plt


r=[]

rpt=pd.DataFrame() #創建紀錄策略參數的DF
bcolnames=['totalm','totalrate','winrate','maxdd','maxconwin','maxconloss','avgconwin','avgconloss']
rpt=pd.DataFrame(np.zeros(1))
rpt.columns=['totalm']
conwin=[]
conloss=[]
    for i in range(0,len(bcolnames)):
        text="rpt['"+bcolnames[i]+"']=0"
        exec(text) 
for i in range(0,100):
      P=df.iloc[:,i]
      cumret=P/100-1
      r = P.diff() / P
      r1=r.drop([0])
      conwin=count_win(r)
      conloss=count_loss(r)
      rpt.at[i,'winrate']=sum(r1>0)/len(r1)
      rpt.at[i,'totalm']=df.iloc[250,i]
      rpt.at[i,'totalrate']=df.iloc[250,i]/100-1
      rpt.at[i,'maxdd']= MAXDDM(P)*-1
      rpt.at[i,'maxconwin']=max(conwin)
      rpt.at[i,'maxconloss']=max(conloss)
      rpt.at[i,'avgconwin']=np.mean(conwin)
      rpt.at[i,'avgconloss']=np.max(conloss)


        
def count_win(r):      
    conwin=[]        
    #r.pop(0)      
    cur_win=0
    max_win=0
    for i in r:
        if i >0:   # 如果当前元素和上一个元素相同,连续出现次数+1,并更新最大值
            cur_win += 1
            max_win = max((cur_win, max_win))
        else:   # 不同则刷新计数器
            if cur_win!=0:
                conwin.append(cur_win )
            cur_win = 0
    return conwin



def MAXDDM(retm):
    highwatermark=np.zeros(len(retm))
    drawdown=np.zeros(len(retm))
    highwatermark[0]=retm[0]
    for i in range(1,len(retm)):
      highwatermark[i]=highwatermark[i-1]
      highwatermark[i]=max(highwatermark[i],retm[i])   
      drawdown[i]=(highwatermark[i]-retm[i])/highwatermark[i]
    return(max(drawdown))



------------------python 程式碼----------------------