目录
- 前言:行文思路
- 1、模块导入
- 2、数据获取
- 3、股票数据类型转换
- 4、回测系统编写
- 5、策略编写
- 6、实例化策略
- 非面向对象的编程
- 分析总结
2022.12.3更新:由于一些因素不得不将文章中的大部分代码进行删除,但行文思路还是完整的,大家可以根据自己的想法思考形成独特的交易策略填充到省略号部分,如需以前的代码可私信了解
前言:行文思路
由于本文篇幅较长,而且文中关于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_shortlong2 = day.s_longshort1 = trade_days[ind - 1].s_shortlong1 = trade_days[ind - 1].s_longif pd.isna(long1):continueif flag == 1:changes_list_1.append(day.change)print("日期:{},持有中".format(day.date))if short2 > long2 and short1 < long1:flag = 1print("日期:{},买入策略执行".format(day.date))if short2 < long2 and short1 > long1:flag = 0print("日期:{},卖出策略执行".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.changeyesterday_down = trade_days[ind - 1].changeif 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 += 1print("日期:{},买入策略执行".format(day.date))if today_down < 0 and yesterday_down < 0 and today_down + yesterday_down < -0.01:flag = 0print("日期:{},卖出策略执行".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)
可以看出策略对该股票进行回测交易时,获得的盈利并不客观,甚至出现较大的亏损,因此,需要对相关策略进行参数调整修改,或者发掘其他更为有效的策略……
最后,大家如果觉得文章写的不错的话,可以点赞、收藏、关注三连哦~文中出现的所有代码已经打包上传至我的资源了,可以下载下来研究分析和运行查看