目錄
- 前言:行文思路
- 1、子產品導入
- 2、資料擷取
- 3、股票資料類型轉換
- 4、回測系統編寫
- 5、政策編寫
- 6、執行個體化政策
- 非面向對象的程式設計
- 分析總結
前言:行文思路
由于本文篇幅較長,而且文中關于python資料分析的知識點、python金融量化的知識點較多,是以在文章的開頭先給出本文整體思路,以便讀者能夠擁有較為清晰的脈絡通讀全文。
第一部分:子產品導入,主要是将後面需要用到的子產品進行導入(簡單,非重點)
第二部分:資料擷取,鑒于在網絡上股票資料不易找到,Wind金融終端等資料庫資料收費,通過多方查找,終于讓我找到了能夠免費下載下傳股票資料的子產品,建議大家收藏(簡單,非重點)
第三部分:将股票資料轉化為新的資料類型,通過上面的方法下載下傳下來的資料類型是我們常見的DataFrame,雖然pandas的功能已經很強大了,但是為了加入新的資料名額以及友善下一步操作,最好還是将DataFrame資料轉化為一種新的資料類型(較難,非重點)
第四部分:政策編寫,也就是利用代碼将我們在股票市場中的交易原則表達出來(較難,重點)
第五部分:回測系統編寫,股票回測即是基于曆史已經發生過的真實行情資料,在曆史上某一段時間内,模拟真實金融市場中股票的買入、賣出,得出這個時間段内的盈利率等資料(較難,重點)
第六部分:執行個體化政策并回測得到收益,繼承一個政策類,得到一個實際的例子,利用股票資料回測得出結果(簡單,重點)
1、子產品導入
import akshare as ak
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
......
akshare:用于下載下傳股票的交易資料(前複權)
collections:對基本資料類型做進一步處理,實作特定的資料類型
abc:主要定義了基本類和最基本的抽象方法,可以為子類定義共有的接口API,不需要具體實作
2、資料擷取
# 擷取某一隻股票一段時間的資料
stock_sz300750_df = ak.stock_zh_a_daily(symbol="sz300750", start_date="20200103", end_date="20211231", adjust="qfq")
# list_date = list(stock_sz300750_df['date'])
# stock_sz300750_df.index = list_date
stock_sz300750_df.head()
函數ak.stock_zh_a_daily()用于擷取A股股票資料
symbol為股票代碼,sh為上交所股票,sz為深交所股票;strat_date、end_date分别為股票資料開始時間、結束時間;adjust預設為不複權的資料, qfq是傳回前複權後的資料,hfq是 傳回後複權後的資料
3、股票資料類型轉換
由于後面寫了兩個量化交易政策,而且政策中的有部分名額不相同,是以在這一部分以及下面回測系統兩部分面向對象程式設計,有部分函數隻用于政策一,有部分隻用于政策二。
# 将股票資料轉化為新的資料類型
class StockTradeDays(object):
def __init__(self, price_array, date_array=None):
。。。。。。
相同名額:date、price、change
政策一:s_short、s_long分别為5日移動平均線和30日移動平均線;可以根據自己的需求更改參數資料
政策二:函數filter_stock(),用于判斷交易日股票是上漲還是下跌
最後将DataFrame資料轉換為自定義資料類型OrderedDict
4、回測系統編寫
class TradeStrategyBase(ABC, object):
def buy_strategy(self, *args, **kwargs):
。。。。。。
def sell_strategy(self, *args, **kwargs):
。。。。。。
class TradeLoopBack(object):
def __init__(self, trade_days, trade_strategy):
。。。。。。
def execute_trade(self):
。。。。。。
execute_trade()函數中,利用循環周遊整一個交易時段,将獲得的每日股票資料傳給交易政策進行判斷,最終确定是買入、賣出還是持有
5、政策編寫
class TradeStrategy1(TradeStrategyBase):
"""
交易政策1: 利用5日移動平均線與30日移動平均線交叉點進行股票買賣
當5日移動平均線從下往上穿過30日移動平均線時,買入股票并持有
當5日移動平均線從上往下穿過30日移動平均線時,賣出股票
"""
def buy_strategy(self, trade_ind, trade_day, trade_days):
。。。。。。
def sell_strategy(self, trade_ind, trade_day, trade_days):
。。。。。。
移動平均線是将一定時期内的股票價格加以平均,把不同時間的平均值連接配接起來形成一根MA,利用長短期的移動平均線交叉點觀察股票價格變動趨勢的一種技術名額。是以,隻有到了第30天才可以獲得30日移動平均值,才可能進行買賣。
判斷買入條件:當短期移動平均線從下往上穿過長期移動平均線時,可以認為短期内股價的趨勢向上,股價可能會上漲
判斷賣出條件:當短期移動平均線從上往下穿過長期移動平均線時,可以認為短期内股價的趨勢向下,股價可能會下跌
class TradeStrategy2(TradeStrategyBase):
"""
交易政策2: 追漲殺跌政策,當股價連續兩個交易日上漲
且上漲幅度超過閥值預設s_buy_change_threshold(),買入股票并持有
當股價連續兩個交易日下跌
且下跌幅度超過閥值預設s_sell_change_threshold(),賣出股票
"""
def buy_strategy(self, trade_ind, trade_day, trade_days):
。。。。。。
def sell_strategy(self, trade_ind, trade_day, trade_days):
。。。。。。
政策二可以認為是非理性人在股票市場中交易時,遇到多日上漲且上漲幅度較大時,會認為股票有繼續上漲的趨勢,為了獲利是以買入股票;但當某一股票連續下跌且下跌幅度超過心理預期時,會認為股票又繼續下跌的趨勢,為了止損賣出股票。
政策二中買入股票條件為:當股價連續兩個交易日上漲且上漲幅度超過0.05,買入股票并持有
賣出條件為:當股價連續兩個交易日下跌且下跌幅度超過-0.05,賣出股票
相關參數可以根據需求修改
6、執行個體化政策
經過前面的所有步驟之後,就可以執行個體化一個交易政策,利用交易資料進行回測,可得到相應的結果:
結果:
非面向對象的程式設計
由于對面向對象程式設計不太擅長,是以我對兩個政策又分别寫了新的程式,以判斷上文面向對象程式是否正确
changes_list_1 = []
flag = -1
for ind, day in enumerate(trade_days):
short2 = day.s_short
long2 = day.s_long
short1 = trade_days[ind - 1].s_short
long1 = trade_days[ind - 1].s_long
if pd.isna(long1):
continue
if flag == 1:
changes_list_1.append(day.change)
print("日期:{},持有中".format(day.date))
if short2 > long2 and short1 < long1:
flag = 1
print("日期:{},買入政策執行".format(day.date))
if short2 < long2 and short1 > long1:
flag = 0
print("日期:{},賣出政策執行".format(day.date))
print('回測政策1總盈虧為:{}%'.format(reduce(lambda a, b: a + b, changes_list_1) * 100))
plt.plot(np.array(changes_list_1).cumsum())
結果:
# 政策2
changes_list_2 = []
flag = 0
for ind, day in enumerate(trade_days):
today_down = day.change
yesterday_down = trade_days[ind - 1].change
if flag > 0:
changes_list_2.append(day.change)
print("日期:{},持有中".format(day.date))
if today_down > 0 and yesterday_down > 0 and today_down + yesterday_down > 0.01:
flag += 1
print("日期:{},買入政策執行".format(day.date))
if today_down < 0 and yesterday_down < 0 and today_down + yesterday_down < -0.01:
flag = 0
print("日期:{},賣出政策執行".format(day.date))
print('回測政策2總盈虧為:{}%'.format(reduce(lambda a, b: a + b, changes_list_2) * 100))
plt.plot(np.array(changes_list_2).cumsum())
結果:
分析總結
以上政策隻用于量化分析,并不适合用于實際交易,之是以有較高的盈利,得益于甯王領銜的新能源闆塊的強勢,大家也可以試試其他的股票,比如藥明康德(代碼:SH603259)
可以看出政策對該股票進行回測交易時,獲得的盈利并不客觀,甚至出現較大的虧損,是以,需要對相關政策進行參數調整修改,或者發掘其他更為有效的政策……