Files
my_wiki/raw/量化/abuquant-src/python/c3.py
T

440 lines
15 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- encoding:utf-8 -*-
from __future__ import print_function
import warnings
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
warnings.filterwarnings('ignore')
sns.set_context(rc={'figure.figsize': (14, 7)})
"""
第三章 量化工具——NumPy
abu量化系统github地址:https://github.com/bbfamily/abu (您的star是我的动力!)
abu量化文档教程ipython notebookhttps://github.com/bbfamily/abu/tree/master/abupy_lecture
"""
def sample_311():
"""
3.1.1 并行化思想
:return:
"""
# 注意 * 3的操作被运行在每一个元素上
np_list = np.ones(5) * 3
print('np_list:', np_list)
# 普通的列表把*3操作认为是整体性操作
normal_list = [1, 1, 1, 1, 1] * 3
print('normal_list:', normal_list, len(normal_list))
# 200支股票
stock_cnt = 200
# 504个交易日
view_days = 504
# 生成服从正态分布:均值期望=0,标准差=1的序列
stock_day_change = np.random.standard_normal((stock_cnt, view_days))
try:
# 使用沙盒数据,目的是和书中一样的数据环境,不需要注视掉
stock_day_change = np.load('../gen/stock_day_change.npy')
except Exception as e:
print('../gen/stock_day_change.npy load error:{}'.format(e))
def sample_312():
"""
3.1.2 初始化操作
:return:
"""
np_list = np.arange(10000)
# 100个0
print('np.zeros(100):\n', np.zeros(100))
# shape3行2列 全是0
print('np.zeros((3, 2):\n', np.zeros((3, 2)))
# shape 3行2列 全是1
print('np.ones((3, 2):\n', np.ones((3, 2)))
# shapex=2, y=3, z=3 值随机
print('np.empty((2, 3, 3):\n', np.empty((2, 3, 3)))
# 初始化序列与np_list一样的shape,值全为1
print('np.ones_like(np_list):\n', np.ones_like(np_list))
# 初始化序列与np_list一样的shape,值全为0
print('np.zeros_like(np_list):\n', np.zeros_like(np_list))
# eye得到对角线全为1的单位矩阵
print('np.eye(3):\n', np.eye(3))
# 打印shape (200, 504) 200行504列
print('stock_day_change.shape:', stock_day_change.shape)
# 打印出第一支只股票,头五个交易日的涨跌幅情况
print('stock_day_change[0:1, :5]:\n', stock_day_change[0:1, :5])
"""
3.1.3 索引选取和切片选
"""
# tmp = a
tmp = stock_day_change[0:2, 0:5].copy()
# a = b
stock_day_change[0:2, 0:5] = stock_day_change[-2:, -5:]
# b = tmp
stock_day_change[-2:, -5:] = tmp
def sample_313():
"""
3.1.3 索引选取和切片选
:return:
"""
# 0:2第一,第二支股票,0:5头五个交易日的涨跌幅数据
print('stock_day_change[0:2, 0:5]:\n', stock_day_change[0:2, 0:5])
# -2:倒数一,第二支股票,-5:最后五个交易日的涨跌幅数据
print('stock_day_change[-2:, -5:]:\n', stock_day_change[-2:, -5:])
# view result
print('[0:2, 0:5], [-2:, -5:]:\n', stock_day_change[0:2, 0:5], stock_day_change[-2:, -5:])
def sample_314():
"""
3.1.4 数据转换与规整
:return:
"""
print('stock_day_change[0:2, 0:5]:\n', stock_day_change[0:2, 0:5])
print('[0:2, 0:5].astype(int):\n', stock_day_change[0:2, 0:5].astype(int))
# 2代表保留两位小数
print('around 2:\n', np.around(stock_day_change[0:2, 0:5], 2))
# 使用copy目的是不修改原始序列
tmp_test = stock_day_change[0:2, 0:5].copy()
# 将第一个元素改成nan
tmp_test[0][0] = np.nan
print('tmp_test:\n', tmp_test)
def sample_315():
"""
3.1.5 逻辑条件进行数据筛选
:return:
"""
# 找出上述切片内涨幅超过0.5的股票时段, 通过输出结果你可以看到返回的是boolean的数组
mask = stock_day_change[0:2, 0:5] > 0.5
print('mask:\n', mask)
tmp_test = stock_day_change[0:2, 0:5].copy()
# 使用上述的mask数组筛选出符合条件的数组, 即中筛选mask中对应index值为True的
print('tmp_test[mask]:\n', tmp_test[mask])
tmp_test[tmp_test > 0.5] = 1
print('tmp_test:\n', tmp_test)
tmp_test = stock_day_change[-2:, -5:]
print('tmp_test2:\n', tmp_test)
print('tmp_test[(tmp_test > 1) | (tmp_test < -1)]:\n', tmp_test[(tmp_test > 1) | (tmp_test < -1)])
# noinspection PyTypeChecker
def sample_316():
"""
3.1.6 通用序列函数
:return:
"""
# np.all判断序列中的所有元素是否全部是true, 即对bool序列进行与操作
# 本例实际判断stock_day_change[0:2, 0:5]中是否全是上涨的
print('np.all(stock_day_change[0:2, 0:5] > 0):\n', np.all(stock_day_change[0:2, 0:5] > 0))
# np.any判断序列中是否有元素为true, 即对bool序列进行或操作
# 本例实际判断stock_day_change[0:2, 0:5]中是至少有一个是上涨的
print('np.any(stock_day_change[0:2, 0:5] > 0):\n', np.any(stock_day_change[0:2, 0:5] > 0))
# 对两个序列对应的元素两两比较,maximum结果集取大,相对使用minimum为取小的结果集
print('np.maximum(stock_day_change[0:2, 0:5], stock_day_change[-2:, -5:]):\n',
np.maximum(stock_day_change[0:2, 0:5], stock_day_change[-2:, -5:]))
change_int = stock_day_change[0:2, 0:5].astype(int)
print('change_int:\n', change_int)
# 序列中数值值唯一且不重复的值组成新的序列
print('np.unique(change_int):\n', np.unique(change_int))
# axis1
print('np.diff(stock_day_change[0:2, 0:5]):\n', np.diff(stock_day_change[0:2, 0:5]))
# 唯一区别 axis=0
print('np.diff(stock_day_change[0:2, 0:5], axis=0):\n', np.diff(stock_day_change[0:2, 0:5], axis=0))
tmp_test = stock_day_change[-2:, -5:]
print('np.where(tmp_test > 0.5, 1, 0):\n', np.where(tmp_test > 0.5, 1, 0))
print('np.where(tmp_test > 0.5, 1, tmp_test):\n', np.where(tmp_test > 0.5, 1, tmp_test))
# 序列中的值大于0.5并且小于1的赋值为1,否则赋值为0
print('np.where(np.logical_and(tmp_test > 0.5, tmp_test < 1), 1, 0):\n',
np.where(np.logical_and(tmp_test > 0.5, tmp_test < 1), 1, 0))
# 序列中的值大于0.5或者小于-0.5的赋值为1,否则赋值为0
print('np.where(np.logical_or(tmp_test > 0.5, tmp_test < -0.5), 1, 0):\n',
np.where(np.logical_or(tmp_test > 0.5, tmp_test < -0.5), 1, 0))
"""
3.1.7 数据本地序列化操作
"""
stock_day_change = np.load('../gen/stock_day_change.npy')
np.save('../gen/stock_day_change', stock_day_change)
"""
3.2 统计概念与函数使用
"""
stock_day_change_four = stock_day_change[:4, :4]
def sample_320():
"""
3.2.0 统计概念与函数使用
:return:
"""
print('stock_day_change_four:\n', stock_day_change_four)
def sample_321():
"""
3.2.1 统计基础函数使用
:return:
"""
print('最大涨幅 {}'.format(np.max(stock_day_change_four, axis=1)))
print('最大跌幅 {}'.format(np.min(stock_day_change_four, axis=1)))
print('振幅幅度 {}'.format(np.std(stock_day_change_four, axis=1)))
print('平均涨跌 {}'.format(np.mean(stock_day_change_four, axis=1)))
print('最大涨幅 {}'.format(np.max(stock_day_change_four, axis=0)))
print('最大涨幅股票{}'.format(np.argmax(stock_day_change_four, axis=0)))
print('最大跌幅股票{}'.format(np.argmin(stock_day_change_four, axis=0)))
print('最大跌幅 {}'.format(np.min(stock_day_change_four, axis=0)))
print('振幅幅度 {}'.format(np.std(stock_day_change_four, axis=0)))
print('平均涨跌 {}'.format(np.mean(stock_day_change_four, axis=0)))
def sample_322():
"""
3.2.2 统计基础概念
:return:
"""
a_investor = np.random.normal(loc=100, scale=50, size=(100, 1))
b_investor = np.random.normal(loc=100, scale=20, size=(100, 1))
# a交易者
print('a交易者期望{0:.2f}元, 标准差{1:.2f}, 方差{2:.2f}'.format(
a_investor.mean(), a_investor.std(), a_investor.var()))
# b交易者
print('b交易者期望{0:.2f}元, 标准差{1:.2f}, 方差{2:.2f}'.format(
b_investor.mean(), b_investor.std(), b_investor.var()))
# a交易者期望
a_mean = a_investor.mean()
# a交易者标注差
a_std = a_investor.std()
# 收益绘制曲线
plt.plot(a_investor)
# 水平直线 上线
plt.axhline(a_mean + a_std, color='r')
# 水平直线 均值期望线
plt.axhline(a_mean, color='y')
# 水平直线 下线
plt.axhline(a_mean - a_std, color='g')
plt.show()
b_mean = b_investor.mean()
b_std = b_investor.std()
# b交易者收益绘制曲线
plt.plot(b_investor)
# 水平直线 上线
plt.axhline(b_mean + b_std, color='r')
# 水平直线 均值期望线
plt.axhline(b_mean, color='y')
# 水平直线 下线
plt.axhline(b_mean - b_std, color='g')
plt.show()
def sample_331():
"""
3.3.1 正态分布基础概念
:return:
"""
import scipy.stats as scs
# 均值期望
stock_mean = stock_day_change[0].mean()
# 标准差
stock_std = stock_day_change[0].std()
print('股票0 mean均值期望:{:.3f}'.format(stock_mean))
print('股票0 std振幅标准差:{:.3f}'.format(stock_std))
# 绘制股票0的直方图
plt.hist(stock_day_change[0], bins=50, normed=True)
# linspace从股票0 最小值-> 最大值生成数据
fit_linspace = np.linspace(stock_day_change[0].min(),
stock_day_change[0].max())
# 概率密度函数(PDFprobability density function)
# 由均值,方差,来描述曲线,使用scipy.stats.norm.pdf生成拟合曲线
pdf = scs.norm(stock_mean, stock_std).pdf(fit_linspace)
print(pdf)
# plot x, y
plt.plot(fit_linspace, pdf, lw=2, c='r')
plt.show()
def sample_332():
"""
3.3.2 实例1:正态分布买入策略
:return:
"""
# 保留后50天的随机数据作为策略验证数据
keep_days = 50
# 统计前454, 切片切出0-454dayview_days = 504
stock_day_change_test = stock_day_change[:stock_cnt, 0:view_days - keep_days]
# 打印出前454跌幅最大的三支,总跌幅通过np.sum计算,np.sort对结果排序
print('np.sort(np.sum(stock_day_change_test, axis=1))[:3]:', np.sort(np.sum(stock_day_change_test, axis=1))[:3])
# 使用np.argsort针对股票跌幅进行排序,返回序号,即符合买入条件的股票序号
stock_lower_array = np.argsort(np.sum(stock_day_change_test, axis=1))[:3]
# 输符合买入条件的股票序号
print('stock_lower_array:', stock_lower_array)
def show_buy_lower(p_stock_ind):
"""
:param p_stock_ind: 股票序号,即在stock_day_change中的位置
:return:
"""
# 设置一个一行两列的可视化图表
_, axs = plt.subplots(nrows=1, ncols=2, figsize=(16, 5))
# view_days504 - keep_days50 = 454
# 绘制前454天股票走势图,np.cumsum():序列连续求和
axs[0].plot(np.arange(0, view_days - keep_days),
stock_day_change_test[p_stock_ind].cumsum())
# [view_days504 - keep_days50 = 454 : view_days504]
# 从第454天开始到504天的股票走势
cs_buy = stock_day_change[p_stock_ind][
view_days - keep_days:view_days].cumsum()
# 绘制从第454天到504天股票走势图
axs[1].plot(np.arange(view_days - keep_days, view_days), cs_buy)
# 返回从第454天开始到第504天计算盈亏的盈亏序列的最后一个值
return cs_buy[-1]
# 最后输出的盈亏比例
profit = 0
# 跌幅最大的三支遍历序号
for stock_ind in stock_lower_array:
# profit即三支股票从第454天买入开始计算,直到最后一天的盈亏比例
profit += show_buy_lower(stock_ind)
plt.show()
# str.format 支持{:.2f}形式保留两位小数
print('买入第 {} 支股票,从第454个交易日开始持有盈亏:{:.2f}%'.format(
stock_lower_array, profit))
def sample_342():
"""
3.4.2 实例2:如何在交易中获取优势
:return:
"""
# 设置100个赌徒
gamblers = 100
def casino(win_rate, win_once=1, loss_once=1, commission=0.01):
"""
赌场:简单设定每个赌徒一共有1000000一共想在赌场玩10000000次,
但是你要是没钱了也别想玩了
win_rate: 输赢的概率
win_once: 每次赢的钱数
loss_once: 每次输的钱数
commission: 手续费这里简单的设置了0.01 1%
"""
my_money = 1000000
play_cnt = 10000000
commission = commission
for _ in np.arange(0, play_cnt):
# 使用伯努利分布根据win_rate来获取输赢
w = np.random.binomial(1, win_rate)
if w:
# 赢了 +win_once
my_money += win_once
else:
# 输了 -loss_once
my_money -= loss_once
# 手续费
my_money -= commission
if my_money <= 0:
# 没钱就别玩了,不赊账
break
return my_money
"""
如果有numba使用numba进行加速, 这个加速效果非常明显,不使用numba非常非常非常慢
"""
import numba as nb
casino = nb.jit(casino)
print('heaven_moneys....')
# 100个赌徒进场天堂赌场,胜率0.5,赔率1,还没手续费
heaven_moneys = [casino(0.5, commission=0) for _ in
np.arange(0, gamblers)]
print('cheat_moneys....')
# 100个赌徒进场开始,胜率0.4,赔率1,没手续费
cheat_moneys = [casino(0.4, commission=0) for _ in
np.arange(0, gamblers)]
print('commission_moneys....')
# 100个赌徒进场开始,胜率0.5,赔率1,手续费0.01
commission_moneys = [casino(0.5, commission=0.01) for _ in
np.arange(0, gamblers)]
print('casino(0.5, commission=0.01, win_once=1.02, loss_once=0.98.....')
# 100个赌徒进场开始,胜率0.5,赔率1.04,手续费0.01
f1_moneys = [casino(0.5, commission=0.01, win_once=1.02, loss_once=0.98)
for _ in np.arange(0, gamblers)]
print('casino(0.45, commission=0.01, win_once=1.02, loss_once=0.98.....')
# 100个赌徒进场开始,胜率0.45,赔率1.04,手续费0.01
f2_moneys = [casino(0.45, commission=0.01, win_once=1.02, loss_once=0.98)
for _ in np.arange(0, gamblers)]
_ = plt.hist(heaven_moneys, bins=30)
plt.show()
_ = plt.hist(cheat_moneys, bins=30)
plt.show()
_ = plt.hist(commission_moneys, bins=30)
plt.show()
_ = plt.hist(f1_moneys, bins=30)
plt.show()
_ = plt.hist(f2_moneys, bins=30)
plt.show()
if __name__ == "__main__":
sample_311()
# sample_312()
# sample_313()
# sample_314()
# sample_315()
# sample_316()
# sample_320()
# sample_321()
# sample_322()
# sample_331()
# sample_332()
# sample_342()