這裏並非爲了說明技術分析可行,也不是爲了說明技術分析不可行,僅是以我淺薄的知識驗證一些事情,測試方法及測試結果都會公佈以下.python
至於測試方法是否嚴謹, 就請讀者自行判斷吧。git
這裏隨機選擇300支股票,並下載最近七年的日內行情數據.github
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支股票用於這次測試。json
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文件框架
執行結果以下dom
最後數據文件結構以下:ide
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源碼分析
策略的選擇原則是不會涵蓋大量的計算。單純經過開收高低、前復權收盤價、交易量這些基本數據用於決策買入賣出。post
注: 關於策略的選擇以及其參數這裏有很大的主觀成分。測試
選擇策略以下
雙均線策略應該是最簡單的策略了,主要原理是,選擇一條短時間的移動平均線,一條長期的移動平均線,當短時間移動平均線向上突破長期移動平均線則買入,反之,則賣出。
這裏選擇10日的短時間移動平均線,25日的長期移動平均線。
這個策略用來隨機選擇買入時間點,而後20個交易往後賣出.
瞧瞧隨機的力量。
倉位: 經過市場波動性調整及管理倉位.具體計算流程以下。
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
計算觸發值
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天。
因爲代碼段並不是幾十行, 會佔據文章很大篇幅,請參考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
收益圖以下
輸出以下
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 = 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[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的源碼分析以及使用說明.