381 lines
13 KiB
Python
381 lines
13 KiB
Python
# -*- encoding:utf-8 -*-
|
||
"""
|
||
abupy中使用的金融时间序列分析模块, 模块真的方法真的参数都为abupy中格式化好的kl如下
|
||
|
||
eg:
|
||
close high low p_change open pre_close volume date date_week key atr21 atr14
|
||
2016-07-20 228.36 229.800 225.00 1.38 226.47 225.26 2568498 20160720 2 499 9.1923 8.7234
|
||
2016-07-21 220.50 227.847 219.10 -3.44 226.00 228.36 4428651 20160721 3 500 9.1711 8.7251
|
||
2016-07-22 222.27 224.500 218.88 0.80 221.99 220.50 2579692 20160722 4 501 9.1858 8.7790
|
||
2016-07-25 230.01 231.390 221.37 3.48 222.27 222.27 4490683 20160725 0 502 9.2669 8.9298
|
||
2016-07-26 225.93 228.740 225.63 -1.77 227.34 230.01 41833 20160726 1 503 9.1337 8.7541
|
||
"""
|
||
|
||
from __future__ import absolute_import
|
||
from __future__ import division
|
||
from __future__ import print_function
|
||
|
||
from collections import Iterable
|
||
|
||
import logging
|
||
|
||
import numpy as np
|
||
import pandas as pd
|
||
|
||
from ..CoreBu import ABuEnv
|
||
from ..CoreBu.ABuPdHelper import pd_resample
|
||
|
||
__author__ = '阿布'
|
||
__weixin__ = 'abu_quant'
|
||
|
||
log_func = logging.info if ABuEnv.g_is_ipython else print
|
||
|
||
|
||
def _df_dispatch(df, dispatch_func):
|
||
"""
|
||
根据df的类型分发callable的执行方法,
|
||
|
||
:param df: abupy中格式化好的kl,或者字典,或者可迭代序列
|
||
:param dispatch_func: 分发的可执行的方法
|
||
"""
|
||
if isinstance(df, pd.DataFrame):
|
||
# 参数只是pd.DataFrame
|
||
return dispatch_func(df)
|
||
elif isinstance(df, dict) and all([isinstance(_df, pd.DataFrame) for _df in df.values()]):
|
||
# 参数只是字典形式
|
||
return [dispatch_func(df[df_key], df_key) for df_key in df]
|
||
elif isinstance(df, Iterable) and all([isinstance(_df, pd.DataFrame) for _df in df]):
|
||
# 参数只是可迭代序列
|
||
return [dispatch_func(_df) for _df in df]
|
||
else:
|
||
log_func('df type is error! {}'.format(type(df)))
|
||
|
||
|
||
def _df_dispatch_concat(df, dispatch_func):
|
||
"""
|
||
根据df的类型分发callable的执行方法,如果是字典或者可迭代类型的返回值使用
|
||
pd.concat连接起来
|
||
|
||
:param df: abupy中格式化好的kl,或者字典,或者可迭代序列
|
||
:param dispatch_func: 分发的可执行的方法
|
||
"""
|
||
|
||
if isinstance(df, pd.DataFrame):
|
||
# 参数只是pd.DataFrame
|
||
return dispatch_func(df)
|
||
elif isinstance(df, dict) and all([isinstance(_df, pd.DataFrame) for _df in df.values()]):
|
||
# 参数只是字典形式
|
||
return pd.concat([dispatch_func(df[df_key], df_key) for df_key in df], axis=1)
|
||
elif isinstance(df, Iterable) and all([isinstance(_df, pd.DataFrame) for _df in df]):
|
||
# 参数只是可迭代序列
|
||
return pd.concat([dispatch_func(_df) for _df in df], axis=1)
|
||
else:
|
||
log_func('df type is error! {}'.format(type(df)))
|
||
|
||
|
||
def resample_close_mean(df, bins=None):
|
||
"""
|
||
对金融时间序列进行变换周期重新采样,对重新采样的结果进行pct_change处理
|
||
,对pct_change序列取abs绝对值,对pct_change绝对值序列取平均,即算出
|
||
重新采样的周期内的平均变化幅度
|
||
|
||
eg:
|
||
tsla = ABuSymbolPd.make_kl_df('usTSLA')
|
||
ABuKLUtil.resample_close_mean(tsla)
|
||
|
||
out:
|
||
resample
|
||
5D 0.0340
|
||
10D 0.0468
|
||
21D 0.0683
|
||
42D 0.0805
|
||
60D 0.1002
|
||
90D 0.0931
|
||
120D 0.0939
|
||
|
||
:param df: abupy中格式化好的kl,或者字典,或者可迭代序列
|
||
:param bins: 默认eg: ['5D', '10D', '21D', '42D', '60D', '90D', '120D']
|
||
:return: pd.DataFrame
|
||
"""
|
||
|
||
def _resample_close_mean(p_df, df_name=''):
|
||
resample_dict = {}
|
||
for _bin in bins:
|
||
change = abs(pd_resample(p_df.close, _bin, how='mean').pct_change()).mean()
|
||
"""
|
||
eg: pd_resample(p_df.close, bin, how='mean')
|
||
|
||
2014-07-23 249.0728
|
||
2014-09-03 258.3640
|
||
2014-10-15 240.8663
|
||
2014-11-26 220.1552
|
||
2015-01-07 206.0070
|
||
2015-02-18 198.0932
|
||
2015-04-01 217.9791
|
||
2015-05-13 251.3640
|
||
2015-06-24 266.4511
|
||
2015-08-05 244.3334
|
||
2015-09-16 236.2250
|
||
2015-10-28 222.0441
|
||
2015-12-09 222.0574
|
||
2016-01-20 177.2303
|
||
2016-03-02 226.8766
|
||
2016-04-13 230.6000
|
||
2016-05-25 216.7596
|
||
2016-07-06 222.6420
|
||
|
||
abs(pd_resample(p_df.close, bin, how='mean').pct_change())
|
||
|
||
2014-09-03 0.037
|
||
2014-10-15 0.068
|
||
2014-11-26 0.086
|
||
2015-01-07 0.064
|
||
2015-02-18 0.038
|
||
2015-04-01 0.100
|
||
2015-05-13 0.153
|
||
2015-06-24 0.060
|
||
2015-08-05 0.083
|
||
2015-09-16 0.033
|
||
2015-10-28 0.060
|
||
2015-12-09 0.000
|
||
2016-01-20 0.202
|
||
2016-03-02 0.280
|
||
2016-04-13 0.016
|
||
2016-05-25 0.060
|
||
2016-07-06 0.027
|
||
|
||
abs(pd_resample(p_df.close, bin, how='mean').pct_change()).mean():
|
||
|
||
0.080
|
||
"""
|
||
resample_dict[_bin] = change
|
||
resample_df = pd.DataFrame.from_dict(resample_dict, orient='index')
|
||
resample_df.columns = ['{}resample'.format(df_name)]
|
||
return resample_df
|
||
|
||
if bins is None:
|
||
bins = ['5D', '10D', '21D', '42D', '60D', '90D', '120D']
|
||
return _df_dispatch_concat(df, _resample_close_mean)
|
||
|
||
|
||
def bcut_change_vc(df, bins=None):
|
||
"""
|
||
eg:
|
||
tsla = ABuSymbolPd.make_kl_df('usTSLA')
|
||
ABuKLUtil.bcut_change_vc(tsla)
|
||
|
||
out:
|
||
p_change rate
|
||
(0, 3] 209 0.4147
|
||
(-3, 0] 193 0.3829
|
||
(3, 7] 47 0.0933
|
||
(-7, -3] 44 0.0873
|
||
(-10, -7] 6 0.0119
|
||
(7, 10] 3 0.0060
|
||
(10, inf] 1 0.0020
|
||
(-inf, -10] 1 0.0020
|
||
|
||
:param df: abupy中格式化好的kl,或者字典,或者可迭代序列
|
||
:param bins: 默认eg:[-np.inf, -10, -7, -3, 0, 3, 7, 10, np.inf]
|
||
:return: pd.DataFrame
|
||
"""
|
||
|
||
def _bcut_change_vc(p_df, df_name=''):
|
||
dww = pd.DataFrame(pd.cut(p_df.p_change, bins=bins).value_counts())
|
||
# 计算各个bin所占的百分比
|
||
dww['{}rate'.format(df_name)] = dww.p_change.values / dww.p_change.values.sum()
|
||
if len(df_name) > 0:
|
||
dww.rename(columns={'p_change': '{}'.format(df_name)}, inplace=True)
|
||
return dww
|
||
|
||
if bins is None:
|
||
bins = [-np.inf, -10, -7, -3, 0, 3, 7, 10, np.inf]
|
||
return _df_dispatch_concat(df, _bcut_change_vc)
|
||
|
||
|
||
def qcut_change_vc(df, q=10):
|
||
"""
|
||
eg:
|
||
tsla = ABuSymbolPd.make_kl_df('usTSLA')
|
||
ABuKLUtil.qcut_change_vc(tsla)
|
||
|
||
out:
|
||
change
|
||
0 [-10.45, -3.002]
|
||
1 (-3.002, -1.666]
|
||
2 (-1.666, -0.93]
|
||
3 (-0.93, -0.396]
|
||
4 (-0.396, 0.065]
|
||
5 (0.065, 0.48]
|
||
6 (0.48, 1.102]
|
||
7 (1.102, 1.922]
|
||
8 (1.922, 3.007]
|
||
9 (3.007, 11.17]
|
||
|
||
:param df: abupy中格式化好的kl,或者字典,或者可迭代序列
|
||
:param q: 透传qcut使用的q参数,默认10,10等分
|
||
:return: pd.DataFrame
|
||
"""
|
||
|
||
def _qcut_change_vc(p_df, df_name=''):
|
||
dww = pd.qcut(p_df.p_change, q).value_counts().index.values
|
||
# 构造Categories使用DataFrame套Series
|
||
dww = pd.Series(dww)
|
||
# 涨跌从负向正开始排序
|
||
dww.sort_values(inplace=True)
|
||
dww = pd.DataFrame(dww)
|
||
# 排序后index重新从0开始排列
|
||
dww.index = np.arange(0, q)
|
||
dww.columns = ['{}change'.format(df_name)]
|
||
return dww
|
||
|
||
return _df_dispatch_concat(df, _qcut_change_vc)
|
||
|
||
|
||
def date_week_mean(df):
|
||
"""
|
||
eg:
|
||
|
||
tsla = ABuSymbolPd.make_kl_df('usTSLA')
|
||
ABuKLUtil.date_week_mean(tsla)
|
||
|
||
out:
|
||
周一 0.0626
|
||
周二 0.0475
|
||
周三 0.0881
|
||
周四 0.2691
|
||
周五 -0.2838
|
||
:param df: abupy中格式化好的kl,或者字典,或者可迭代序列
|
||
:return: pd.Series或者pd.DataFrame
|
||
"""
|
||
|
||
def _date_week_win(p_df, df_name=''):
|
||
dww = p_df.groupby('date_week')['p_change'].mean()
|
||
# 将周几这个信息变成中文
|
||
dww.rename(index={6: '周日', 0: '周一', 1: '周二', 2: '周三', 3: '周四', 4: '周五', 5: '周六'},
|
||
inplace=True)
|
||
# p_change变成对应的pchange
|
||
dww = pd.DataFrame(dww)
|
||
dww.rename(columns={'p_change': '{}_p_change'.format(df_name)}, inplace=True)
|
||
return dww
|
||
|
||
return _df_dispatch_concat(df, _date_week_win)
|
||
|
||
|
||
def date_week_win(df):
|
||
"""
|
||
eg:
|
||
tsla = ABuSymbolPd.make_kl_df('usTSLA')
|
||
ABuKLUtil.date_week_win(tsla)
|
||
|
||
out:
|
||
0 1 win
|
||
date_week
|
||
0 44 51 0.5368
|
||
1 55 48 0.4660
|
||
2 48 57 0.5429
|
||
3 44 57 0.5644
|
||
4 53 47 0.470
|
||
|
||
:param df: bupy中格式化好的kl,或者字典,或者可迭代序列
|
||
:return: pd.Series或者pd.DataFrame
|
||
"""
|
||
|
||
def _date_week_win(p_df, df_name=''):
|
||
_df = p_df.copy()
|
||
win_key = '{}win'.format(df_name)
|
||
_df[win_key] = _df['p_change'] > 0
|
||
_df[win_key] = _df[win_key].astype(int)
|
||
|
||
dww = pd.concat([pd.crosstab(_df.date_week, _df[win_key]), _df.pivot_table([win_key], index='date_week')],
|
||
axis=1)
|
||
# 将周几这个信息变成中文
|
||
# noinspection PyUnresolvedReferences
|
||
dww.rename(index={6: '周日', 0: '周一', 1: '周二', 2: '周三', 3: '周四', 4: '周五', 5: '周六'}, inplace=True)
|
||
return dww
|
||
|
||
return _df_dispatch_concat(df, _date_week_win)
|
||
|
||
|
||
def wave_change_rate(df):
|
||
"""
|
||
eg:
|
||
tsla = ABuSymbolPd.make_kl_df('usTSLA')
|
||
ABuKLUtil.wave_change_rate(tsla)
|
||
|
||
out:
|
||
日振幅涨跌幅比:1.794156
|
||
|
||
:param df: abupy中格式化好的kl,或者字典,或者可迭代序列
|
||
"""
|
||
|
||
def _wave_change_rate(p_df, df_name=''):
|
||
wave = ((p_df.high - p_df.low) / p_df.pre_close) * 100
|
||
# noinspection PyUnresolvedReferences
|
||
wave_rate = wave.mean() / np.abs(p_df['p_change']).mean()
|
||
|
||
print('{}日振幅涨跌幅比:{:2f}, {}日统计套利条件'.format(
|
||
df_name, wave_rate, '具备' if wave_rate > 1.80 else '不具备'))
|
||
_df_dispatch(df, _wave_change_rate)
|
||
|
||
|
||
def p_change_stats(df):
|
||
"""
|
||
eg :
|
||
tsla = ABuSymbolPd.make_kl_df('usTSLA')
|
||
ABuKLUtil.p_change_stats(tsla)
|
||
|
||
out:
|
||
|
||
日涨幅平均值1.861, 共260个交易日上涨走势
|
||
日跌幅平均值-1.906, 共244个交易日下跌走势
|
||
日平均涨跌比0.977, 上涨下跌数量比:1.066
|
||
|
||
:param df: abupy中格式化好的kl,或者字典,或者可迭代序列
|
||
"""
|
||
|
||
def _p_change_stats(p_df, df_name=''):
|
||
p_change_up = p_df[p_df['p_change'] > 0].p_change
|
||
p_change_down = p_df[p_df['p_change'] < 0].p_change
|
||
print('{}日涨幅平均值{:.3f}, 共{}个交易日上涨走势'.format(df_name, p_change_up.mean(), p_change_up.count()))
|
||
print('{}日跌幅平均值{:.3f}, 共{}个交易日下跌走势'.format(df_name, p_change_down.mean(), p_change_down.count()))
|
||
print('{}日平均涨跌比{:.3f}, 上涨下跌数量比:{:.3f}\n'.format(
|
||
df_name, abs(p_change_up.mean() / p_change_down.mean()), p_change_up.count() / p_change_down.count()))
|
||
|
||
_df_dispatch(df, _p_change_stats)
|
||
|
||
|
||
def date_week_wave(df):
|
||
"""
|
||
根据周几分析金融时间序列中的日波动:
|
||
|
||
eg:
|
||
tsla = ABuSymbolPd.make_kl_df('usTSLA')
|
||
ABuKLUtil.date_week_wave(tsla)
|
||
|
||
out:
|
||
usTSLAwave
|
||
date_week
|
||
周一 3.8144
|
||
周二 3.3326
|
||
周三 3.3932
|
||
周四 3.3801
|
||
周五 2.9923
|
||
|
||
:param df: abupy中格式化好的kl,或者字典,或者可迭代序列
|
||
:return: pd.Series或者pd.DataFrame
|
||
"""
|
||
|
||
def _date_week_wave(p_df, df_name=''):
|
||
# 要改df所以copy
|
||
df_copy = p_df.copy()
|
||
wave_key = '{}wave'.format(df_name)
|
||
# 计算波动: * 100目的是和金融序列中的p_change单位一致
|
||
df_copy[wave_key] = ((df_copy.high - df_copy.low) / df_copy.pre_close) * 100
|
||
dww = df_copy.groupby('date_week')[wave_key].mean()
|
||
# 将周几这个信息变成中文
|
||
dww.rename(index={6: '周日', 0: '周一', 1: '周二', 2: '周三', 3: '周四', 4: '周五', 5: '周六'}, inplace=True)
|
||
return dww
|
||
|
||
return _df_dispatch_concat(df, _date_week_wave)
|