1、简单分析
# 阿里股票历史数据下载:https://www.nasdaq.com/symbol/baba/historical
# 也可以抓取雪球等股票app的数据
# 阿里股票走势图:https://xueqiu.com/S/BABA
# 道琼斯走势:https://xueqiu.com/S/.DJI
mport numpy as np
from dateutil.parser import parse
# 指定打开的文件名
# 不需要的行需要skip掉
# 默认没有分隔符,所以需要指定delimiter
# 不加载全部的情况下需要指定加载哪些列usecols
# 希望把每一列加载到单独的数组中需要设置unpack=True,并指定对应的变量名,列举下有unpack和没有的区别
stock_info = np.loadtxt('./BABA_stock.csv', delimiter=',', usecols=(1, 2, 3,
4, 5), skiprows=1)
stock_info = np.loadtxt('./BABA_stock.csv', delimiter=',', usecols=(1, 2, 3, 4,5), skiprows=1, unpack=True)
stock_info.shape
stock_info = stock_info[:, ::-1]
stock_info
# 上涨下跌的天数
close_info = stock_info[0]
open_info = stock_info[2]
# 上涨
rise_count = len(close_info[open_info - close_info > 0])
# rise_count = close_info[open_info - close_info > 0].size
print('rise count:' + str(rise_count))
# 下跌
fail_count = len(close_info[open_info - close_info <= 0])
print('fail count:' + str(fail_count))
# 上张天数占比
rise_count / close_info.size
close_info
# 日线转换为周线
# 什么是周线
high_info = stock_info[3]
low_info = stock_info[4]
# loadtxt方法有一个converters参数,可以利用自定义的函数把string做转换
def convert_date(d):
return parse(d).weekday()
stock_info = np.loadtxt('./BABA_stock.csv', delimiter=',', usecols=(0, 1, 3, 4,
5), skiprows=1, dtype='S', converters={0: convert_date})
#print(stock_info)
# 倒序排列
stock_info = stock_info[::-1, :].astype('f8')
# 需要按照每周去分组
# 先找到星期一的数据的索引
week_split = np.where(stock_info[:, 0] == 0)[0]
# 按照周一去分组,split返回给定索引的分组
# 可以指定任意间隔的索引,所以split以一个list的形式返回
week_infos_temp = np.split(stock_info, week_split)
print(type(week_infos_temp))
# 为了简单起见,我们这里只使用一周数据有五天的,
week_infos_temp
week_info = [ x for x in week_infos_temp if len(x) == 5 ]
# 每个星期的数据都是一样的了,我们在把他转换成ndarray
w = np.array(week_info)
print(w.shape)
print(w[:3])
week_open = w[:, 0, 3]
print(week_open[:3])
week_close = w[:, -1, 1]
print(week_close[:3])
week_high = w[:, :, 3].max(axis=1)
print(week_high[:3])
week_low = w[:, :, 4].min(axis=1)
print(week_low[:3])
w_info = np.array([week_open, week_close, week_high, week_close])
#print(w_info[:3])
# 一周的数据放到一行,可以直接用转置矩阵
print('result:', w_info.T)
# 结果保存到文件
np.savetxt('./week_info_baba.cvs', w_info.T, header='open, close, high, low',
delimiter=',', fmt='%.2f')
2、股票买卖策略评估
# 加载数据,把date这一列设置为索引,简单起见,只用收盘价进行分析
import numpy as np
import pandas as pd
df = pd.read_csv('./BABA_stock.csv', index_col='date', usecols=[0, 1])
# 先查看以下数据
df.head()
# 将索引转换为datetime形式
df.index = pd.DatetimeIndex(df.index.str.strip("'"))
df.index
# 数据中最近的日期排在前面,按照日期重新排序
df.sort_index(inplace=True)
print(df.head())
df.describe()
# 策略一:股价超出10日均线买入,跌破十日均线卖出
# 先计算10日均线数据
ma10 = df.rolling(10).mean().dropna()
# 买点
ma10_model = df['close'] - ma10['close'] > 0
ma10_model
# 第一个值False,第二个值是True,在True的时候买入,需要自定义一个移动窗口处理函数
# 因为卖的时候还需要定义类似的函数,所以这里把这两个函数放在一起
# 可以在自定义函数中print一些信息,例如w值,以方便调试---这也是调试的一种方式
def get_deal_date(w, is_buy=True):
if is_buy == True:
return True if w[0] == False and w[1] == True else False
else :
return True if w[0] == True and w[1] == False else False
# raw=False没有的话会有警告信息
# 如果删除Na值,会有缺失,所以这里用0填充,转换为bool值方便后面取值
se_buy = ma10_model.rolling(2).apply(get_deal_date,
raw=False).fillna(0).astype('bool')
# apply的args接受数组或者字典给自定义函数传参
se_sale = ma10_model.rolling(2).apply(get_deal_date, raw=False, args=
[False]).fillna(0).astype('bool')
# 具体的买卖点
buy_info = df[se_buy.values]
sale_info = df[se_sale.values]
# print(buy_info.head())
# print(sale_info.head())
# 买和卖的索引值不一样,不过数据都有63条,所以删除时间索引信息
no_index_buy_info = buy_info.reset_index(drop=True)
no_index_sale_info = sale_info.reset_index(drop=True)
# print(no_index_buy_info.head())
# print(no_index_sale_info.head())
# 每次交易的盈利情况
profit = no_index_sale_info - no_index_buy_info
print(profit)
# 大体数据
profit.describe()
# 总利润是36.07,注意这是每次买和卖一股的利润(买固定的股数),三年的时间交易了63次
# 最多投入210.86,平均投入143.366954,按最高投入算利润率(36.07 / 210.860000),年化差不多
5%,按平均投入算0.2515,年化将近8%,当然还有手续费没有算
profit.sum()
# 假如有1w美元,最终盈利是多少
all_money = 10000
remain = all_money
for i in range(len(no_index_buy_info)):
buy_count = remain / no_index_buy_info.iloc[i]
remain = buy_count * no_index_sale_info.iloc[i]
# all_money = sale_total - all_money
print(remain)
# 最后剩下13799.294014,年化10%多点,还不错
# 如果加上每次交易金额的万分之三手续费
all_money = 10000
remain = all_money
fee = 0.0003
for i in range(len(no_index_buy_info)):
buy_count = remain / no_index_buy_info.iloc[i]
remain = buy_count * no_index_sale_info.iloc[i] * (1 - fee)
# all_money = sale_total - all_money
print(remain)
# 最终金额13540.898129,少了一点,不过也还不错
# 将10日线改为60日线试试
# 考虑一种边界情况,买了之后卖点到现在还没有出现(因为是先买的,所以不可能买点比卖点多)
# 这种情况我们把当前的股价加到卖点数据中(也可以把买点数据删除)
print(len(no_index_buy_info))
print(len(no_index_sale_info))
if (len(no_index_buy_info) > len(no_index_sale_info)):
# no_index_buy_info.drop(no_index_buy_info.index[-1], inplace=True)
no_index_sale_info.loc[len(no_index_sale_info)] = [df.iloc[-1, 0]]
# 在看下250天,也是盈利的,不是策略多牛逼,而是这个统计区间是在美股大的上升趋势中
# 从五日线一直到250日线,都回测下,然后找出最高的