數據分析之A股市場技術分析是否可行
這裏並不是為了說明技術分析可行,也不是為了說明技術分析不可行,僅是以我淺薄的知識驗證一些事情,測試方法及測試結果都會公布如下.
至於測試方法是否嚴謹, 就請讀者自行判斷吧。
數據獲取
這裏隨機選擇300支股票,並下載最近七年的日內行情數據.
導入必要庫
import tushare as ts
import random
import os
import json
import datetime
篩選股票
num = 300 code_lis = [] # 獲取中小板數據 zxb_df = ts.get_gem_classified() zxb_lis = list(zxb_df.code) # 獲取滬深三百 hs300_df = ts.get_hs300s() hs300_lis = list(hs300_df.code) # 依次從中小板,滬深300中隨機選取 num/2支股票代碼 zxb_rand = random.sample(zxb_lis, int(num / 2)) hs300_rand = random.sample(hs300_lis, int(num / 2)) # 保存到code_lis並保存 code_lis.extend(zxb_rand) code_lis.extend(hs300_rand) with open(code_file, "w") as wf: json.dump(code_lis, wf) return code_lis
篩選說明: 隨機從中小板以及滬深300裏面隨機各選擇150支股票用於此次測試。
下載數據
download_path = "download" now = datetime.datetime.now() start_time = now - datetime.timedelta(days=years * 365) start = start_time.strftime("%Y-%m-%d") try: print("{} 正在下載".format(code)) df = ts.get_k_data(code, start=start) print("{} 下載完成".format(code)) except Exception as e: print("{} 下載失敗".format(code)) return # 新建Adj Close字段 df["Adj Close"] = df.close # 將tushare下的數據的字段保存為pyalgotrade所要求的數據格式 df.columns = ["Date", "Open", "Close", "High", "Low", "Volume", "code", "Adj Close"] # 將數據保存成本地csv文件 df.to_csv(save_path, index=False)
可直接執行源代碼 裏面的downloader.py文件
執行結果如下
最後數據文件結構如下:
Date,Open,Close,High,Low,Volume,code,Adj Close 2011-03-10,5.606,5.488,5.606,5.477,308493.0,000001,5.488 2011-03-11,5.464,5.42,5.501,5.413,230166.0,000001,5.42 2011-03-14,5.403,5.461,5.467,5.4,217999.0,000001,5.461 2011-03-15,5.41,5.349,5.437,5.302,284381.0,000001,5.349 2011-03-16,5.356,5.386,5.403,5.315,242075.0,000001,5.386 2011-03-17,5.342,5.305,5.369,5.295,207262.0,000001,5.305 2011-03-18,5.366,5.346,5.366,5.319,145243.0,000001,5.346 2011-03-21,5.336,5.326,5.366,5.309,160157.0,000001,5.326
註: 這裏下載每只股票最近七年的日內行情數據,但是並不是所有的公司都上市了七年。
源代碼參考:donwloader.py
策略選取
策略的選擇原則是不會涵蓋大量的計算。單純通過開收高低、前復權收盤價、交易量這些基本數據用於決策買入賣出。
註: 關於策略的選擇以及其參數這裏有很大的主觀成分。
選擇策略如下
雙均線策略
雙均線策略應該是最簡單的策略了,主要原理是,選擇一條短期的移動平均線,一條長期的移動平均線,當短期移動平均線向上突破長期移動平均線則買入,反之,則賣出。
這裏選擇10日的短期移動平均線,25日的長期移動平均線。
隨機策略
這個策略用來隨機選擇買入時間點,然後20個交易日後賣出.
瞧瞧隨機的力量。
海龜交易策略
- 市場: A股市場
-
倉位: 通過市場波動性調整及管理倉位.具體計算流程如下。
-
True Range
True Range = Maximum(H ? L, H ? PDC, PDC ? L)
公式中, True Range代表一天內的波動量,H為當日最高價, L為當日最低價, PDC為前一日收盤價.
-
N
N= (19 * PDN + TR) / 20
公式中:TR為True Range,即一天波動量,PDN為前一日N值。如果沒有PDN則取TR的二十日平均值.
-
Doller Volatility
Dollar Volatility =N ?DollarsPerPoint
公式中, Dollar Volatility指的是波動的價格,Dollars per Point指的是標的股票每波動一個最小單位,1手股票的總價格變化量。在國內最小變化量是0.01元,1手是100股。所以Dollars per Point就是0.01×100=1
-
Unit
Unit = (1 % of AccountMarketDollar) / Volatility
公式中, Unit即為我們買賣的單位,1% of Account是總資產的1%,Market Dollar Volatility就是我們之前算出的Dollar Volatility,通過此公式計算出的Unit就是我們要買入的單位數量。此公式的意義是在一般情況下(市場波動率不大的時候),如果買入1Unit單位的資產,當天震幅使得總資產的變化不超過1%
-
-
入市: 海龜有兩個交易系統,可以自由選擇,這裏只選擇系統一。
系統一
1.若當前價格高於過去20日的最高價,則買入一個Unit(註意是分鐘回測)
2.加倉:若股價在上一次買入(或加倉)的基礎上上漲了0.5N,則加倉一個Unit
系統二
與系統一相一致,但當如破55日最高價時才購買
1.若當前價格高於過去55日的最高價,則買入一個Unit.
1.加倉:若股價在上一次買入(或加倉)的基礎上上漲了0.5N,則加倉一個Unit
Example:若某只股票A的N為2,20日最高價為100,則當股價突破100時買入一個Unit,當股價突破100+0.5×2=101時加倉一個Unit,當股價突破101+0.5×2=102時加倉一個Unit。
-
止盈:
系統一
當股價跌破10日內最低價時(10日唐奇安通道下沿),清空頭寸結束本次交易
系統二
當股價跌破20日內最低價時(20日唐奇安通道下沿),清空頭寸結束本次交易
-
技巧: 資金的調整。
開始時設定兩個比例:Loss和Adjust。若交易結束後損失的資金占總資金比例大於Loss,則今後只用現有投資資金的Adjust比例。
Example:若初始資金為100萬,設定Loss=80%,Adjust=90%。則當總資產低於100×80%=80萬時,進行一次資金調整,以後只使用80×90%=72萬的資金用於投資行為
參考鏈接:https://www.joinquant.com/post/c1747eae8096b5028e471892bef0cf1d?f=stydy&m=algorithm
Dual Thrust交易策略
-
計算觸發值
1)N日High的最高價HH, N日Close的最低價LC;
(2)N日Close的最高價HC,N日Low的最低價LL;
(3)Range = Max(HH-LC,HC-LL)
(4)BuyLine = Open + K * Range
(5)SellLine = Open + K * Range
策略模型參考下圖
-
入市
(1)當價格向上突破上軌時,如果當時持有空倉,則先平倉,再開多倉;如果沒有倉位,則直接開多倉;
(2)當價格向下突破下軌時,如果當時持有多倉,則先平倉,再開空倉;如果沒有倉位,則直接開空倉;
用於A股只能做過所以不用賣空策略賣空策略用於離市.K值使用0.3, 由於這個k值沒有參數調優過,完全是隨便想的值,所以可能讓dual thrust策略的效果沒有發揮到最大。
- 止損: 無
這裏N日的值取15天。
參考鏈接: https://www.joinquant.com/post/274
源代碼
由於代碼段並非幾十行, 會占據文章很大篇幅,請參考GitHub鏈接:stock-analysis
測試結果分析
分析說明: 由於個人水平有限,所以只能以我淺薄的知識來解釋我看到的,如果你有興趣做出自己的解讀,可以翻看源代碼,自行測試。就不用說我業余了,我的確是業余玩家^_^
再者這裏的測試至少是存在以下問題的。
- 實際交易中,在漲停板或跌停板不一定能買得進去或賣的出去.
- 實際交易中買入或賣出的價格並沒有回測中那麽理想
- 實際交易中,不會只買一只股票。
我關註的測試結果主要如下:
- 該策略是否適用於所有股票,即測試的所有股票都能盈利麽,如果不是,那麽盈利的概率如何。
- 回撤比例。
所以選擇以下指標用於分析結果
- 最終收益情況
- 最大回測比例
- 交易次數
最終產生數據格式如下
code,cum return,end,max drawdown,start,trade count
000008,99.6340721572,2018-03-12,37.6096792448,2011-03-22,24
000060,-34.5886186243,2018-03-12,49.0665092914,2011-03-15,35
000063,36.5405019876,2018-03-12,44.1047335728,2011-03-15,38
000069,-61.6228879039,2018-03-12,64.7843454103,2011-03-15,41
000100,88.7160620486,2018-03-12,44.7998410399,2011-03-15,29
這裏的cum return指累計收益,max drawdown指最大回撤比例,單位都是%
上證指數走勢圖
首先瞧瞧上證指數走勢圖
執行以下命令
python index_data.py
這裏選擇近七年的數據,我覺得還是可以的,因為有橫盤期,上漲期,下跌期,所以可以檢驗策略是否能夠逃過下跌期,以及能不能在橫盤期有所作為。因為本文可能更註重的是如何獲取數據,及編寫策略,最後數據分析
以下輸出通過執行以下命令:
python strategy_sma.py index
python strategy_random.py index
python strategy_dual_trust.py index
上證指數雙均線策略收益圖
輸出如下
start at 2011-03-16
Total trades: 35
Final portfolio value: $1399434.50
Cumulative returns: 39.94 %
Max. drawdown: 31.97 %
end at 2018-03-13
收益圖如下
上證指數隨機策略收益圖
輸出如下
Total trades: 73
Final portfolio value: $1173928.61
Cumulative returns: 17.39 %
Max. drawdown: 38.10 %
end at 2018-03-13
收益圖如下
上證指數daul thrust策略收益圖
輸出如下
start at 2011-03-16
Total trades: 32
Final portfolio value: $1860958.06
Cumulative returns: 86.10 %
Max. drawdown: 21.70 %
end at 2018-03-13
收益圖如下
值得註意的是用tushare下載的上證指數的數據可能是有問題的,因為2015-03-27這天的最低價(Low)居然大於開盤價(Open)!!!
這裏對上證指數的回測是基於上證指數可買,並且價格是指數值,並且可買一股。
股票雙均線策略結果
# 讀取雙均線策略輸出結果
sma = pd.read_csv("result/strategy_sma.csv")
# 查看數據前5條
sma.head()
code cum return end max drawdown start trade count
0 8 99.634072 2018-03-12 37.609679 2011-03-22 24
1 60 -34.588619 2018-03-12 49.066509 2011-03-15 35
2 63 36.540502 2018-03-12 44.104734 2011-03-15 38
3 69 -61.622888 2018-03-12 64.784345 2011-03-15 41
4 100 88.716062 2018-03-12 44.799841 2011-03-15 29
# 統計結果
sma.describe()
code cum return max drawdown trade count
count 299.000000 299.000000 299.000000 299.000000
mean 348897.023411 52.958878 46.737723 24.498328
std 202821.008968 127.114389 14.790231 12.048942
min 8.000000 -70.380766 4.832993 0.000000
25% 300140.500000 -16.502707 37.721394 13.000000
50% 300452.000000 20.156509 46.572972 29.000000
75% 600192.500000 73.175792 58.063121 34.000000
max 603858.000000 1236.661103 78.002843 42.000000
股票隨機策略結果
rand = pd.read_csv("result/strategy_random.csv")
rand.head()
Out[120]:
code cum return end max drawdown start trade count
0 8 57.171853 2018-03-12 42.133326 2011-03-22 41
1 60 0.717321 2018-03-12 64.914506 2011-03-15 64
2 63 38.541158 2018-03-12 63.594804 2011-03-15 58
3 69 -13.064397 2018-03-12 48.498738 2011-03-15 70
4 100 48.973887 2018-03-12 42.911270 2011-03-15 58
rand.describe()
Out[121]:
code cum return max drawdown trade count
count 299.000000 299.000000 299.000000 299.000000
mean 348897.023411 37.561896 53.839700 40.755853
std 202821.008968 98.958464 15.073869 20.628316
min 8.000000 -78.754755 6.127005 1.000000
25% 300140.500000 -29.201594 43.073549 22.000000
50% 300452.000000 5.418000 54.826874 45.000000
75% 600192.500000 69.043188 64.120164 59.000000
max 603858.000000 651.783545 90.516418 73.000000
股票dual thrust策略結果
dual = pd.read_csv("result/strategy_dual_trust.csv")
dual.head()
Out[123]:
code cum return end max drawdown start trade count
0 8 -1.724564 2018-03-12 47.924826 2011-03-22 21
1 60 -15.859906 2018-03-12 48.323636 2011-03-15 30
2 63 46.218235 2018-03-12 59.273602 2011-03-15 35
3 69 22.708655 2018-03-12 33.797895 2011-03-15 34
4 100 140.985523 2018-03-12 39.504217 2011-03-15 24
dual.describe()
Out[24]:
code cum return max drawdown trade count
count 299.000000 299.000000 299.000000 299.000000
mean 348897.023411 43.451147 46.518626 21.548495
std 202821.008968 95.254409 17.610361 11.283421
min 8.000000 -71.021800 0.000000 0.000000
25% 300140.500000 -17.341418 33.842472 11.000000
50% 300452.000000 17.209486 46.212199 25.000000
75% 600192.500000 75.395195 60.644285 31.000000
max 603858.000000 838.836061 82.656125 46.000000
由於pyalgotrade框架自身的限制,我在這個交易策略中按照EventWindow的模式自行建立一個EventWindow的類。
海龜交易策略結果
以後補上
收益分析
從上面的回測結果你會發現累計收益無論是最大值還是平均值都是雙均線策略.
交易頻繁的是dual thrust
但是上面的分析其實是有問題的,因為這些股票中有很多的股票可能上市事件不長,所以會產生很大的誤導,因為太短時間的回測有很大的隨機性,這會導致,以為這個策略很好但是,其實知識恰好而已。
當然了, 我這裏的測試,其實也有一個很大的隨機因素的占比。
這裏讓我們將上市時間小於七年的股票去除,再次查看收益情況
回測股票數據如下
python strategy_sma.py
python strategy_randome.py
python strategy_dual_trust.py
雙均線策略
sma[sma.start > pd.to_datetime("2011-03-15")].describe()
Out[32]:
code cum return max drawdown trade count
count 151.000000 151.000000 151.000000 151.000000
mean 332525.701987 31.358881 44.409062 15.390728
std 143561.914878 112.389358 16.168624 10.214352
min 8.000000 -70.380766 4.832993 0.000000
25% 300299.500000 -23.127234 33.424244 6.000000
50% 300470.000000 2.206130 44.971140 13.000000
75% 300637.500000 33.425479 56.288630 24.500000
max 603858.000000 828.628299 78.002843 37.000000
隨機策略
rand[sma.start > pd.to_datetime("2011-03-15")].describe()
Out[33]:
code cum return max drawdown trade count
count 151.000000 151.000000 151.000000 151.000000
mean 332525.701987 17.033825 52.263797 24.821192
std 143561.914878 86.767753 16.254297 15.643140
min 8.000000 -70.347804 6.127005 1.000000
25% 300299.500000 -34.364267 42.012492 10.500000
50% 300470.000000 -4.734439 54.193410 22.000000
75% 300637.500000 40.879252 63.065449 38.500000
max 603858.000000 651.783545 88.746525 60.000000
dual thrus策略
dual[sma.start > pd.to_datetime("2011-03-15")].describe()
Out[34]:
code cum return max drawdown trade count
count 151.000000 151.000000 151.000000 151.000000
mean 332525.701987 24.231603 43.172343 13.284768
std 143561.914878 74.396766 19.763869 9.501142
min 8.000000 -65.661905 0.000000 0.000000
25% 300299.500000 -22.606043 28.152275 5.000000
50% 300470.000000 -0.466305 42.328093 11.000000
75% 300637.500000 48.149141 60.095440 21.500000
max 603858.000000 328.261149 82.357505 35.000000
最後瞧瞧獲得收益的概率
這裏假設最低基準是支付寶的收益,即4%,如果七年後的收益小於31%都是虧損的,計算方法如下。
from math import pow
pow(1.04, 7)
Out[38]: 1.3159317792358403
雙均線策略盈利概率
len(sma[sma.start > pd.to_datetime("2011-03-15")][sma["cum return"] > 31])/len(sma[sma.start > pd.to_datetime("2011-03-15")])
Out[40]: 0.271523178807947
隨機策略盈利概率
len(rand[sma.start > pd.to_datetime("2011-03-15")][rand["cum return"] > 31])/len(rand[sma.start > pd.to_datetime("2011-03-15")])
Out[42]: 0.2913907284768212
dual thrust策略盈利概率
len(dual[sma.start > pd.to_datetime("2011-03-15")][dual["cum return"] > 31])/len(dual[sma.start > pd.to_datetime("2011-03-15")])
Out[43]: 0.2847682119205298
總結
好吧,就收益分析而言居然隨機策略的盈利概率居然大於其他兩個策略,而且概率都小於50%.
這裏的分析還是有很大的局限性,比如數據的頻度,以及樣本的大小。
所以就就這個不太嚴謹的回測分析會發現,在時間長度為七年的條件下,單純技術分析似乎勝率不大,但是這裏沒有在回測之前篩選一些股票,是一個不太現實的問題,比如一些基本面的數據。再者這裏沒有設置調倉,且是全倉。這裏當且僅當是股票分析的一篇分析層次超淺的文章吧。
後面會寫pyalgotrade的源碼分析以及使用說明.
最後的最後
關註以下再走吧。。。^_^
數據分析之A股市場技術分析是否可行