├── __init__.py ├── codes ├── __init__.py ├── result_analyse.py ├── config.py ├── search.py ├── base.py ├── market.py ├── data_generator.py └── regression_test.py ├── output ├── .gitkeeper └── per_200_similars │ └── .gitkeeper ├── test ├── __init__.py ├── unit_test.py └── test.csv ├── result_analyse └── .gitkeeper ├── pic ├── 000001.SZ_simi_result.png ├── 000002.SZ_simi_result.png ├── 000008.SZ_simi_result.png ├── 000009.SZ_simi_result.png ├── 000012.SZ_simi_result.png ├── 000021.SZ_simi_result.png ├── 000025.SZ_simi_result.png ├── 000027.SZ_simi_result.png ├── 000028.SZ_simi_result.png ├── 000001.SZ-30-20160101-person-all.jpg ├── 000001.SZ-30-20160101-euclidean-all.jpg ├── 000001.SZ-30-20150101-euclidean-speed-fft3.jpg ├── 000001.SZ-30-20160101-euclidean-speed-fft3.jpg ├── 000001.SZ-30-20150101-euclidean-speed-fft3-盈利率.jpg ├── 000001.SZ-30-20160101-euclidean-speed-fft3-盈利率.jpg ├── 000001.SZ-30-20150101-euclidean-speed-value-ratio-fft3.jpg ├── 000001.SZ-30-20160101-euclidean-speed-value-ratio-fft3.jpg ├── RegressionTest(250D)-000001.SZ-30-201702024-euclidean-speed-fft3.jpg └── RegressionTest(250D)-000001.SZ-30-201702024-euclidean-speed-wave-fft3.jpg ├── .gitignore ├── wrds ├── data_process.sh ├── make_prediction.sh └── run.sh └── README.md /__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /codes/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /output/.gitkeeper: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /result_analyse/.gitkeeper: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /output/per_200_similars/.gitkeeper: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /pic/000001.SZ_simi_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheersyouran/simi-search/HEAD/pic/000001.SZ_simi_result.png -------------------------------------------------------------------------------- /pic/000002.SZ_simi_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheersyouran/simi-search/HEAD/pic/000002.SZ_simi_result.png -------------------------------------------------------------------------------- /pic/000008.SZ_simi_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheersyouran/simi-search/HEAD/pic/000008.SZ_simi_result.png -------------------------------------------------------------------------------- /pic/000009.SZ_simi_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheersyouran/simi-search/HEAD/pic/000009.SZ_simi_result.png -------------------------------------------------------------------------------- /pic/000012.SZ_simi_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheersyouran/simi-search/HEAD/pic/000012.SZ_simi_result.png -------------------------------------------------------------------------------- /pic/000021.SZ_simi_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheersyouran/simi-search/HEAD/pic/000021.SZ_simi_result.png -------------------------------------------------------------------------------- /pic/000025.SZ_simi_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheersyouran/simi-search/HEAD/pic/000025.SZ_simi_result.png -------------------------------------------------------------------------------- /pic/000027.SZ_simi_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheersyouran/simi-search/HEAD/pic/000027.SZ_simi_result.png -------------------------------------------------------------------------------- /pic/000028.SZ_simi_result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheersyouran/simi-search/HEAD/pic/000028.SZ_simi_result.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea/ 2 | **/__pycache__ 3 | /data 4 | **/raw_data 5 | **/*.zip 6 | **/result_analyse 7 | **/output 8 | .DS_Store -------------------------------------------------------------------------------- /pic/000001.SZ-30-20160101-person-all.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheersyouran/simi-search/HEAD/pic/000001.SZ-30-20160101-person-all.jpg -------------------------------------------------------------------------------- /pic/000001.SZ-30-20160101-euclidean-all.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheersyouran/simi-search/HEAD/pic/000001.SZ-30-20160101-euclidean-all.jpg -------------------------------------------------------------------------------- /pic/000001.SZ-30-20150101-euclidean-speed-fft3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheersyouran/simi-search/HEAD/pic/000001.SZ-30-20150101-euclidean-speed-fft3.jpg -------------------------------------------------------------------------------- /pic/000001.SZ-30-20160101-euclidean-speed-fft3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheersyouran/simi-search/HEAD/pic/000001.SZ-30-20160101-euclidean-speed-fft3.jpg -------------------------------------------------------------------------------- /pic/000001.SZ-30-20150101-euclidean-speed-fft3-盈利率.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheersyouran/simi-search/HEAD/pic/000001.SZ-30-20150101-euclidean-speed-fft3-盈利率.jpg -------------------------------------------------------------------------------- /pic/000001.SZ-30-20160101-euclidean-speed-fft3-盈利率.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheersyouran/simi-search/HEAD/pic/000001.SZ-30-20160101-euclidean-speed-fft3-盈利率.jpg -------------------------------------------------------------------------------- /pic/000001.SZ-30-20150101-euclidean-speed-value-ratio-fft3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheersyouran/simi-search/HEAD/pic/000001.SZ-30-20150101-euclidean-speed-value-ratio-fft3.jpg -------------------------------------------------------------------------------- /pic/000001.SZ-30-20160101-euclidean-speed-value-ratio-fft3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheersyouran/simi-search/HEAD/pic/000001.SZ-30-20160101-euclidean-speed-value-ratio-fft3.jpg -------------------------------------------------------------------------------- /pic/RegressionTest(250D)-000001.SZ-30-201702024-euclidean-speed-fft3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheersyouran/simi-search/HEAD/pic/RegressionTest(250D)-000001.SZ-30-201702024-euclidean-speed-fft3.jpg -------------------------------------------------------------------------------- /pic/RegressionTest(250D)-000001.SZ-30-201702024-euclidean-speed-wave-fft3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cheersyouran/simi-search/HEAD/pic/RegressionTest(250D)-000001.SZ-30-201702024-euclidean-speed-wave-fft3.jpg -------------------------------------------------------------------------------- /wrds/data_process.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #$ -cwd 3 | #$ -m abe 4 | #$ -M yzhanggm@connect.ust.hk 5 | 6 | echo "Starting job at `date`" 7 | 8 | RESULT_FILE=result_info.txt 9 | 10 | #if [ -fe $RESULT_FILE ] 11 | #then 12 | # rm $RESULT_FILE 13 | #fi 14 | 15 | ~/miniconda3/bin/python3 ../codes/data_generator.py >> $RESULT_FILE 16 | 17 | echo "Finished job at `date`" -------------------------------------------------------------------------------- /wrds/make_prediction.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #$ -cwd 3 | #$ -m abe 4 | #$ -M yzhanggm@connect.ust.hk 5 | 6 | echo "Starting job at `date`" 7 | 8 | RESULT_FILE=result_info.txt 9 | 10 | #if [ -fe $RESULT_FILE ] 11 | #then 12 | # rm $RESULT_FILE 13 | #fi 14 | 15 | ~/miniconda3/bin/python3 ../codes/make_prediction.py >> $RESULT_FILE 16 | 17 | echo "Finished job at `date`" -------------------------------------------------------------------------------- /wrds/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #$ -cwd 3 | #$ -m abe 4 | #$ -M yzhanggm@connect.ust.hk 5 | 6 | echo "Starting job at `date`" 7 | 8 | if [ $# -eq 0 ] 9 | then 10 | echo "Error! No arguments supplied!" 11 | exit 1 12 | fi 13 | 14 | RESULT_FILE=$1 15 | 16 | #if [ -fe $RESULT_FILE ] 17 | #then 18 | # rm $RESULT_FILE 19 | #fi 20 | 21 | ~/miniconda3/bin/python3 ../codes/regression_test.py >> $RESULT_FILE 22 | 23 | echo "Finished job at `date`" -------------------------------------------------------------------------------- /codes/result_analyse.py: -------------------------------------------------------------------------------- 1 | from scipy.stats.stats import pearsonr 2 | import tushare as ts 3 | from codes.config import * 4 | 5 | if __name__ == '__main__': 6 | data = pd.read_csv(config.rootPath + '/result_analyse/pred_2018-05-18.csv') 7 | data.columns = ['CODE', 'DATE', 'P1', 'P2', 'P3', 'P4', 'P5', 'P10', 'P20'] 8 | data = data.dropna() 9 | codes = data['CODE'].values 10 | 11 | act = [] 12 | for code in codes: 13 | p = ts.get_k_data(code.split('.')[0], start='2018-05-17', end='2018-05-18') 14 | a = p['close'] / p['close'].shift(1) - 1 15 | act.append(a.values[1]) 16 | 17 | data['A1'] = act 18 | data = data.sort_values(ascending=True, by=['P1']) 19 | 20 | percentage5 = round(data.shape[0] * 0.05) 21 | for i in [1, 2, 3, 4, 5, 6]: 22 | nb = percentage5 * i 23 | print('\nPercentage: ', i * 5, '% (', nb, ')') 24 | long = data.head(nb) 25 | short = data.tail(nb) 26 | 27 | pos = long['A1'].mean() 28 | neg = short['A1'].mean() 29 | 30 | print('pos: ', pos) 31 | print('neg: ', neg) 32 | 33 | p1 = pearsonr(data['P1'].values, act)[0] 34 | 35 | print('\npearsonr', p1) -------------------------------------------------------------------------------- /test/unit_test.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import pandas as pd 3 | from codes.config import config 4 | 5 | class UnitTest(unittest.TestCase): 6 | time_series1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 7 | time_series2 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] * 10 8 | 9 | def test_market_pass_days(self): 10 | from codes.market import market 11 | date1 = '2017-01-03' 12 | self.assertEqual(str(market.pass_days(date1, 1).date()), '2017-01-04') 13 | self.assertEqual(str(market.pass_days(date1, 6).date()), '2017-01-11') 14 | 15 | config.start_date = pd.to_datetime('2017-01-03') 16 | market._pass_a_week() 17 | self.assertEqual(str(config.start_date), '2017-01-10') 18 | 19 | def test_get_historical_data(self): 20 | config.start_date = pd.to_datetime('2015-11-20') 21 | 22 | from codes.market import market 23 | pattern = market.get_data(start_date=config.start_date, code='603883.SH') 24 | self.assertEqual(pattern.shape[0], 30) 25 | self.assertEqual(str(market.current_date.date()), '2015-12-31') 26 | 27 | def test_pred_ratio(self): 28 | print() 29 | 30 | if __name__ == '__main__': 31 | unittest.main() -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Stock History Similarity Search 2 | 3 | update 13, Feb 多CPU上大规模多空交易 4 | 5 | --- 6 | 7 | ### 全局查找 8 | 9 | **[查找股票]:** 000001.SZ 10 | **[起止时间]:** 2016-01-01 起 30个交易日 11 | **[数据集]:** 中证800五年的日行情数据 12 | **[预处理方式]:** 数据标准化 13 | **[相似衡量]:** 欧氏距离 14 | **[查询时间]:** 662s 15 | 16 | 1 17 | 18 | --- 19 | 20 | ### 基于3级快速傅里叶变换的快速查找 21 | 22 | **[查找股票]:** 000001.SZ 23 | **[起止时间]:** 2016-01-01 起 30个交易日 24 | **[数据集]:** 中证800五年的日行情数据 25 | **[预处理方式]:** 数据标准化、3级快速傅里叶变换 26 | **[相似衡量]:** 欧氏距离 27 | **[查询时间]:** 20s 28 | 29 | 2 30 | 31 | ------ 32 | 33 | ### 基于小波降噪及3级快速傅里叶变换的快速查找(标准化) 34 | 35 | **[查找股票]:** 000001.SZ 36 | **[起止时间]:** 2017-02-24 至 250个交易日 37 | **[数据集]:** 中证800五年的日行情数据 38 | **[预处理方式]:** 数据标准化、3级快速傅里叶变换 39 | **[相似衡量]:** 欧氏距离 40 | **[查询时间]:** 20s 41 | 42 | 2 43 | 44 | ------ 45 | 46 | ### 基于3级快速傅里叶变换的快速查找(盈利率) 47 | 48 | **[查找股票]:** 000001.SZ 49 | **[起止时间]:** 2016-01-01 起 30个交易日 50 | **[数据集]:** 中证800五年的日行情数据 51 | **[预处理方式]:** 盈利率、3级快速傅里叶变换 52 | **[相似衡量]:** 欧氏距离 53 | **[查询时间]:** 20s 54 | 55 | 2 56 | 57 | ------ 58 | 59 | ### 基于3级快速傅里叶变换的回归测试(盈利率) 60 | 61 | **[查找股票]:** 000001.SZ 62 | **[起止时间]:** 2017-02-24 至 250个交易日 63 | **[数据集]:** 中证800五年的日行情数据 64 | **[相似衡量]:** 欧氏距离 65 | 66 | 2 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /codes/config.py: -------------------------------------------------------------------------------- 1 | import pandas as pd 2 | import numpy as np 3 | import os 4 | from datetime import timedelta 5 | import math 6 | 7 | pd.set_option('display.width', 1200) 8 | pd.set_option('precision', 3) 9 | np.set_printoptions(precision=3) 10 | np.set_printoptions(threshold=np.nan) 11 | 12 | 13 | class Config: 14 | __instance = None 15 | def __new__(cls, *args, **kwargs): 16 | if cls.__instance is None: 17 | cls.__instance = object.__new__(cls, *args, **kwargs) 18 | return cls.__instance 19 | 20 | def __init__(self): 21 | print('Init Config!', os.getpid()) 22 | 23 | # 文件路径相关参数 24 | self.rootPath = os.path.split(os.path.abspath(os.path.dirname(__file__)))[0] 25 | self.ZZ800_DATA = self.rootPath + '/data/800_data.csv' 26 | self.ZZ800_RAW_DATA = self.rootPath + '/data/800_raw_data.csv' 27 | self.ZZ800_CODES = self.rootPath + '/data/800_codes.csv' 28 | self.ZZ800_RM_VR_FFT = self.rootPath + '/data/800_rm_vr_fft.csv' 29 | self.MARKET_RATIO = self.rootPath + '/data/index_ratio.csv' 30 | self.TRAINING_DAY = self.rootPath + '/data/trading_day.csv' 31 | 32 | # self.speed_method = 'value_ratio_fft_euclidean' # for 沪深300指数预测 33 | self.speed_method = 'rm_market_vr_fft' # for 沪深800选股 34 | 35 | self.update_start = '2018-05-18' # 更新数据的开始时间(数据库日期的最后一天的下一天) 36 | self.update_end = '2018-05-21' # 更新数据的结束时间(这一天也会被更新下来) 37 | 38 | self.auto_update = False # 回测时是否自动更新数据 39 | self.plot_simi_stock = False # 是否画出相似股票 40 | 41 | # self.is_regression_test = False # 是回测还是预测 42 | # self.start_date = pd.to_datetime('2018-05-16') #回测的开始时间。 比如'2018-01-01',则从'2018-01-02'开始做预测 43 | # self.regression_days = 5 44 | 45 | self.is_regression_test = True 46 | self.start_date = pd.to_datetime('2011-01-01') 47 | self.regression_days = 800 48 | 49 | self.regression_end_date = self.start_date + timedelta(days=self.regression_days) # 回测结束时间 50 | 51 | # 相似性查找参数 52 | self.pattern_length = 30 53 | self.nb_similar_make_prediction = 20 # avergae them as a pred 54 | self.nb_similar_of_all_similar = 4000 # 从所有股票的相似票中选择top N 55 | self.nb_similar_of_each_stock = 200 56 | 57 | self.slide_window = 1500 58 | 59 | self.weighted_dist = True 60 | self.weight_a = 1 61 | self.weight_b = 2 62 | self.alpha = np.multiply([1, 1, 1, 1, 1], 40) 63 | self.beata = np.multiply([1, 1, 1, 1, 1], math.pi / 180) 64 | 65 | self.fft_level = 5 66 | self.similarity_method = 'euclidean' # or 'pearsonr' 67 | 68 | self.cores = 20 69 | self.nb_codes = 800 70 | 71 | # 输出文件地址 72 | name = str(self.start_date.date()) + '_' + str(self.speed_method) + '_' + str(self.nb_similar_make_prediction) 73 | self.PEARSON_CORR_RESLUT = self.rootPath + '/output/corr' + name + '.csv' 74 | self.PRDT_AND_ACT_RESULT = self.rootPath + '/output/pred' + name +'.csv' 75 | self.regression_result = self.rootPath + '/pic/para_' + name + '.png' 76 | 77 | config = Config() 78 | 79 | if __name__ == '__main__': 80 | std_data = pd.read_csv(config.DATA) 81 | -------------------------------------------------------------------------------- /codes/search.py: -------------------------------------------------------------------------------- 1 | from codes.config import * 2 | from scipy.stats.stats import pearsonr 3 | from codes.market import market 4 | from codes.base import plot_simi_stock, norm, weighted_distance 5 | 6 | 7 | def find_similar_of_a_stock(code): 8 | all_data, pattern, targets = market.get_historical_data(end_date=config.start_date, code=code) 9 | 10 | if pattern is None: 11 | print('---Pattern is None for ', code) 12 | return None 13 | 14 | ALPHA = config.alpha 15 | BETA = config.beata 16 | 17 | targets['fft_deg'] = 0 18 | for i in range(config.fft_level): 19 | index = str(i + 1) 20 | p_fft = pattern['fft' + index].tail(1).values 21 | p_deg = pattern['deg' + index].tail(1).values 22 | 23 | targets['fft' + index] = (targets['fft' + index] - p_fft).abs() * ALPHA[i] 24 | targets['deg' + index] = (targets['deg' + index] - p_deg).abs() * BETA[i] 25 | 26 | targets['fft_deg'] += targets['fft' + index] + targets['deg' + index] 27 | 28 | sorted_std_diff = targets[(targets['RET'] != 0)] 29 | sorted_std_diff = sorted_std_diff.sort_values(ascending=True, by=['fft_deg']) 30 | sorted_std_diff = sorted_std_diff.head(config.nb_similar_of_each_stock) 31 | 32 | distances = [] 33 | for _, ith in sorted_std_diff.iterrows(): 34 | result = targets[(targets['CODE'] == targets['CODE']) & (targets['DATE'] <= ith['DATE'])].tail(config.pattern_length) 35 | distances.append(weighted_distance(norm(result['RET'], result['300_RATIO']), 36 | norm(pattern['RET'], pattern['300_RATIO']), 37 | config.pattern_length)) 38 | 39 | sorted_std_diff[config.similarity_method] = distances 40 | tops = sorted_std_diff.sort_values(ascending=True, by=[config.similarity_method]) 41 | 42 | tops['pattern'] = code 43 | if config.plot_simi_stock: 44 | plot_simi_stock(tops.head(config.nb_similar_make_prediction), all_data, pattern, code + '_simi_result', codes=code) 45 | 46 | # if ~config.is_regression_test: 47 | # file_name = config.rootPath + '/output/per_200_similars/' + str(market.current_date.date()) + '_' + code + '_200_similars.csv' 48 | # tops.to_csv(file_name, index=False) 49 | 50 | return tops 51 | 52 | 53 | def predict_stock_base_on_similars(code): 54 | tops = find_similar_of_a_stock(code) 55 | 56 | if tops is None: 57 | return None 58 | 59 | tops = tops.head(config.nb_similar_make_prediction) 60 | pred_ratios1, pred_ratios5, pred_ratios10, pred_ratios20 = 0, 0, 0, 0 61 | 62 | for _, top in tops.iterrows(): 63 | pred = market.get_data(start_date=top['DATE'], code=top['CODE']) 64 | 65 | if config.speed_method in ['rm_market_vr_fft']: 66 | pred_market_ratios1 = market.get_span_market_ratio(pred, 1) 67 | pred_market_ratios5 = market.get_span_market_ratio(pred, 5) 68 | pred_market_ratios10 = market.get_span_market_ratio(pred, 10) 69 | pred_market_ratios20 = market.get_span_market_ratio(pred, 20) 70 | else: 71 | pred_market_ratios1, pred_market_ratios5, pred_market_ratios10, pred_market_ratios20 = 0, 0, 0, 0 72 | 73 | pred_ratios1 += (pred.iloc[1]['CLOSE'] - pred.iloc[0]['CLOSE']) / pred.iloc[0]['CLOSE'] - pred_market_ratios1 74 | pred_ratios5 += (pred.iloc[5]['CLOSE'] - pred.iloc[0]['CLOSE']) / pred.iloc[0]['CLOSE'] - pred_market_ratios5 75 | pred_ratios10 += (pred.iloc[10]['CLOSE'] - pred.iloc[0]['CLOSE']) / pred.iloc[0]['CLOSE'] - pred_market_ratios10 76 | pred_ratios20 += (pred.iloc[20]['CLOSE'] - pred.iloc[0]['CLOSE']) / pred.iloc[0]['CLOSE'] - pred_market_ratios20 77 | 78 | size = tops.shape[0] 79 | return [code, pred_ratios1/size, pred_ratios5/size, pred_ratios10/size, pred_ratios20/size] 80 | 81 | 82 | if __name__ == '__main__': 83 | 84 | all_data, pattern, targets = market.get_historical_data(config.start_date, code=config.code) 85 | 86 | tops = find_similar_of_a_stock(pattern, targets, config.code) 87 | tops = tops.head(config.nb_similar) 88 | plot_simi_stock(tops, all_data, pattern, 'speed_search_' + config.speed_method, codes=config.code) -------------------------------------------------------------------------------- /codes/base.py: -------------------------------------------------------------------------------- 1 | ''' 2 | 工具类 3 | ''' 4 | 5 | #encoding:utf-8 6 | import matplotlib 7 | matplotlib.use('Agg') 8 | import matplotlib.pyplot as plt 9 | from scipy.spatial.distance import euclidean 10 | from codes.config import * 11 | 12 | 13 | def weighted_distance(x, y, length=config.pattern_length): 14 | if config.weighted_dist: 15 | weight = np.arange(config.weight_a, config.weight_b, (config.weight_b - config.weight_a) / length) 16 | dist = np.abs(np.multiply(pd.DataFrame(x).values - pd.DataFrame(y).values, weight.reshape(length, 1))) 17 | return np.sum(dist) 18 | else: 19 | return euclidean(x, y) 20 | 21 | 22 | def norm(X, ratio=None): 23 | if ratio is None: 24 | raise Exception('No Ratios!') 25 | ret_ = X + 1 26 | ratio_ = (ratio / 100) + 1 27 | result = np.divide(ret_, ratio_) 28 | return result 29 | 30 | 31 | def plot_simi_stock(top, data, pattern, filename, codes): 32 | print('plot simi stock of ', codes, ' ...') 33 | 34 | def init_plot_data(): 35 | plot_codes = np.append(top['CODE'].values, codes) 36 | plot_dates = list(top['DATE'].values) 37 | plot_dates.append(None) 38 | plot_prices = np.zeros([config.nb_similar_make_prediction + 1, config.pattern_length]) 39 | plot_legend = list() 40 | plot_market_ratio = np.zeros([config.nb_similar_make_prediction + 1, config.pattern_length]) 41 | return plot_codes, plot_dates, plot_prices, plot_legend, plot_market_ratio 42 | 43 | plot_codes, plot_dates, plot_prices, plot_legend, plot_market_ratio = init_plot_data() 44 | 45 | for i in range(config.nb_similar_make_prediction): 46 | plot_quote = data[data['CODE'] == plot_codes[i]] 47 | plot_quote = plot_quote[plot_quote['DATE'] <= pd.to_datetime(plot_dates[i])].tail(config.pattern_length) 48 | plot_prices[i] = plot_quote['RET'].values 49 | plot_legend.append( 50 | str(plot_codes[i]) + "," + 51 | str(config.similarity_method) + ":" + 52 | str(top.iloc[i][config.similarity_method])) 53 | plot_market_ratio[i] = plot_quote[config.market_ratio_type].values 54 | 55 | plot_prices[-1] = pattern['RET'].values 56 | plot_market_ratio[-1] = pattern[config.market_ratio_type].values 57 | 58 | plot_dates[-1] = pattern['DATE'].iloc[-1] 59 | plot_legend.append(str(plot_codes[-1])) 60 | norm_plot_prices = [norm(plot_prices[i], plot_market_ratio[i]) for i in range(config.nb_similar_make_prediction + 1)] 61 | 62 | # assert for result checking 63 | for i in range(config.nb_similar_make_prediction): 64 | a = weighted_distance(norm_plot_prices[i], norm_plot_prices[-1], config.pattern_length) 65 | b = top.iloc[i][config.similarity_method] 66 | assert a == b, 'calcu error!' 67 | 68 | for i in range(plot_codes.size): 69 | plt.plot(norm_plot_prices[i], label=norm_plot_prices[i], linewidth=1.5) 70 | 71 | plt.xlabel('Time') 72 | plt.ylabel('NAV') 73 | plt.legend(plot_legend, loc='upper left') 74 | plt.title("Similarity Search[" + plot_codes[-1] + "]\n") 75 | plt.grid(True) 76 | plt.xticks(fontsize=8, rotation=45) 77 | plt.ioff() 78 | plt.savefig(config.rootPath + '/pic/' + filename +'.png') 79 | plt.close() 80 | 81 | 82 | def plot_nav_curve(strategy_net_value, act_net_value, market_net_value, dates, turnover_rate): 83 | plt.plot(dates, strategy_net_value, 'r-', label=strategy_net_value, linewidth=1.5) 84 | plt.plot(dates, act_net_value, 'k-', label=act_net_value, linewidth=1.5) 85 | plt.plot(dates, market_net_value, 'g-', label=market_net_value, linewidth=1.5) 86 | 87 | plt.xlabel('Time') 88 | plt.ylabel('Net Asset Value') 89 | plt.legend(['strategy', 'baseline', 'market'], loc='upper left') 90 | plt.title("Turnover rate: " + str(turnover_rate)) 91 | plt.grid(True) 92 | plt.xticks(fontsize=8, rotation=20) 93 | plt.ioff() 94 | plt.savefig(config.regression_result) 95 | plt.close() 96 | 97 | 98 | def compare_plot(x1, x2): 99 | plt.plot(x1) 100 | plt.plot(x2) 101 | plt.grid(True) 102 | plt.ioff() 103 | plt.savefig('../pic/' + 'compare_result.jpg') 104 | plt.close() 105 | 106 | if __name__ == '__main__': 107 | print('') 108 | -------------------------------------------------------------------------------- /codes/market.py: -------------------------------------------------------------------------------- 1 | from codes.config import config 2 | import os 3 | import pandas as pd 4 | import numpy as np 5 | import math 6 | from codes.data_generator import update_data 7 | 8 | 9 | class Market: 10 | __instance = None 11 | def __new__(cls, *args, **kwargs): 12 | if cls.__instance is None: 13 | cls.__instance = object.__new__(cls, *args, **kwargs) 14 | return cls.__instance 15 | 16 | def __init__(self): 17 | print('Init Market! ', os.getpid()) 18 | self.all_data = None 19 | self._init_all_data(config.speed_method) 20 | 21 | self.codes = None 22 | self._init_codes() 23 | 24 | self.trading_days = None 25 | self._init_trading_days() 26 | 27 | self.pattern = None 28 | self.targets = None 29 | self.current_date = config.start_date 30 | 31 | def _init_all_data(self, speed_method=config.speed_method): 32 | 33 | if speed_method == 'value_ratio_fft_euclidean': 34 | file = config.ZZ800_VALUE_RATIO_FFT_DATA 35 | elif speed_method == 'rm_market_vr_fft': 36 | file = config.ZZ800_RM_VR_FFT 37 | 38 | if self.all_data is None: 39 | print('Init All Data! ', os.getpid()) 40 | if config.auto_update: 41 | rm_vr_data, _, __ = update_data() 42 | self.all_data = rm_vr_data 43 | else: 44 | self.all_data = pd.read_csv(file, parse_dates=['DATE'], low_memory=False) 45 | 46 | self.all_data['OPEN'] = 1 47 | 48 | def _init_codes(self): 49 | def apply(x): 50 | if int(x[0]) >= 6: 51 | return x + '.SH' 52 | else: 53 | return x + '.SZ' 54 | 55 | codes = pd.read_csv(config.ZZ800_CODES, dtype={'CODE': str}) 56 | codes['CODE'] = codes['CODE'].apply(func=apply) 57 | self.codes = codes['CODE'].head(config.nb_codes).values.flatten() 58 | 59 | def _init_trading_days(self): 60 | 61 | self.trading_days = pd.read_csv(config.TRAINING_DAY, parse_dates=['DATE']) 62 | 63 | def _pass_a_day(self): 64 | self.current_date = pd.to_datetime(self.trading_days[self.trading_days['DATE'] > self.current_date].head(1).values[0][0]) 65 | config.start_date = pd.to_datetime(self.trading_days[self.trading_days['DATE'] > config.start_date].head(1).values[0][0]) 66 | 67 | def _pass_a_week(self): 68 | self.current_date = pd.to_datetime(self.trading_days[self.trading_days['DATE'] > self.current_date].head(5).tail(1).values[0][0]) 69 | config.start_date = pd.to_datetime(self.trading_days[self.trading_days['DATE'] > config.start_date].head(5).tail(1).values[0][0]) 70 | 71 | def get_historical_data(self, end_date=None, code=None): 72 | 73 | targets = self.all_data[self.all_data['CODE'] != code].reset_index(drop=True) 74 | start = self.trading_days[self.trading_days['DATE'] <= end_date].tail(30).head(1).values[0][0] 75 | 76 | def apply(x): 77 | return x.tail(config.slide_window) 78 | 79 | targets = targets[targets['DATE'] < start].groupby(['CODE']).apply(func=apply) 80 | 81 | self.pattern = self.all_data[(self.all_data['CODE'] == code) & 82 | (self.all_data['DATE'] <= end_date) & 83 | (self.all_data['DATE'] >= start)] 84 | 85 | self.targets = targets.dropna() 86 | 87 | if self.pattern.shape[0] == 0: 88 | return self.all_data, None, self.targets 89 | 90 | self.pattern = self.pattern.reset_index(drop=True) 91 | return self.all_data, self.pattern, self.targets 92 | 93 | def get_data(self, start_date=None, end_date=None, code=None, pattern_length=config.pattern_length): 94 | 95 | all_data = self.all_data 96 | 97 | if code is not None: 98 | if start_date is None and end_date is not None: 99 | pattern = all_data[(all_data['CODE'] == code) & (all_data['DATE'] <= end_date)].tail(pattern_length) 100 | elif start_date is not None and end_date is None: 101 | pattern = all_data[(all_data['CODE'] == code) & (all_data['DATE'] >= start_date)].head(pattern_length) 102 | elif start_date is not None and end_date is not None: 103 | pattern = all_data[(all_data['CODE'] == code) & (all_data['DATE'] <= end_date) & (all_data['DATE'] >= start_date)] 104 | else: 105 | if start_date is None and end_date is not None: 106 | pattern = all_data[(all_data['DATE'] <= end_date)].tail(pattern_length) 107 | elif start_date is not None and end_date is None: 108 | pattern = all_data[(all_data['DATE'] >= start_date)].head(pattern_length) 109 | elif start_date is not None and end_date is not None: 110 | pattern = all_data[(all_data['DATE'] <= end_date) & (all_data['DATE'] >= start_date)] 111 | 112 | return pattern 113 | 114 | def pass_days(self, date, nb_day): 115 | date_ = pd.to_datetime(self.trading_days[self.trading_days['DATE'] > date].head(nb_day).tail(1).values[0][0]) 116 | return date_ 117 | 118 | def get_span_market_ratio(self, df, n): 119 | array = np.cumprod(df['300_RATIO'][1:] / 100 + 1).values 120 | array = np.insert(array, 0, 1) 121 | return 1 if math.isnan(array[n]) else array[n] 122 | 123 | def get_span_ret(self, df, n): 124 | array = np.cumprod(df['RET'][1:] / 100 + 1).values 125 | array = np.insert(array, 0, 1) 126 | return 1 if math.isnan(array[n]) else array[n] 127 | 128 | 129 | market = Market() -------------------------------------------------------------------------------- /codes/data_generator.py: -------------------------------------------------------------------------------- 1 | ''' 2 | 工具类,用于生成新的fft数据 3 | ''' 4 | 5 | import tushare as ts 6 | import pandas as pd 7 | import numpy as np 8 | import os 9 | import sys 10 | 11 | curPath = os.path.abspath(os.path.dirname(__file__)) 12 | rootPath = os.path.split(curPath)[0] 13 | sys.path.append(curPath) 14 | sys.path.append(rootPath) 15 | 16 | from codes.base import norm 17 | from codes.config import config 18 | 19 | 20 | def _format_code(data): 21 | def apply(x): 22 | if int(x[0]) >= 6: 23 | return x + '.SH' 24 | else: 25 | return x + '.SZ' 26 | 27 | data['CODE'] = data['CODE'].apply(func=apply) 28 | return data 29 | 30 | 31 | def get_traiding_day(start=None, end=None): 32 | all_trading_day = pd.read_csv(config.TRAINING_DAY) 33 | all_trading_day.columns = ['DATE', 'OPEN'] 34 | all_trading_day = all_trading_day[all_trading_day['OPEN'] == 1] 35 | 36 | if start is None: 37 | trading_day = all_trading_day[all_trading_day['DATE'] <= end] 38 | elif end is None: 39 | trading_day = all_trading_day[all_trading_day['DATE'] >= start] 40 | else: 41 | trading_day = all_trading_day[(all_trading_day['DATE'] >= start) & (all_trading_day['DATE'] <= end)] 42 | return trading_day, all_trading_day 43 | 44 | 45 | def _gen_zz800_stock_list(): 46 | ''' 47 | :return: 生成中证800股票代码,[code, name, weight, date] 48 | ''' 49 | zz500 = ts.get_zz500s() 50 | hs300 = ts.get_hs300s() 51 | zz800 = zz500.append(hs300) 52 | zz800 = zz800[['code', 'name', 'weight', 'date']] 53 | zz800.columns = zz800.columns.str.upper() 54 | zz800 = zz800.sort_values(ascending=True, by=['CODE']) 55 | zz800.to_csv(config.ZZ800_CODES, index=False) 56 | return zz800 57 | 58 | 59 | def _get_new_zz800_data(trading_day): 60 | 61 | start_date = trading_day.iloc[0]['DATE'] 62 | end_date = trading_day.iloc[-1]['DATE'] 63 | nb_date = trading_day.shape[0] 64 | 65 | codes = _gen_zz800_stock_list()['CODE'] 66 | if codes.empty: 67 | raise Exception('No codes file found!') 68 | 69 | market_ratio = ts.get_hist_data('hs300', start=start_date, end=end_date).reset_index() 70 | datas = [] 71 | for code in codes: 72 | data = ts.get_hist_data(code, start=start_date, end=end_date) 73 | if data is None or data.shape[0] != nb_date: 74 | data = ts.get_k_data(code, start='2010-01-01', end=end_date).reset_index().tail(nb_date + 1) 75 | if data is None or data.shape[0] != nb_date + 1: 76 | print('停牌或找不到:', code) 77 | continue 78 | data['p_change'] = data['close'] / data['close'].shift(1) - 1 79 | 80 | data = data.tail(nb_date) 81 | data['800_ratio'] = 0 82 | data['code'] = code 83 | data = data.reset_index() 84 | datas.append(data[['close', 'code', 'date', 'p_change', '800_ratio']]) 85 | 86 | hist_data = pd.concat(datas) 87 | hist_data.columns = ['close', 'code', 'date', 'ret', '800_ratio'] 88 | hist_data = hist_data.merge(market_ratio[['date', 'p_change']], on=['date'], how='left') 89 | hist_data.columns = ['close', 'code', 'date', 'ret', '800_ratio', '300_ratio'] 90 | hist_data.columns = hist_data.columns.str.upper() 91 | 92 | hist_data = _format_code(hist_data) 93 | return hist_data 94 | 95 | 96 | def update_data(new_dataset=None): 97 | 98 | def update_trading_date(): 99 | trading_day = ts.trade_cal() 100 | trading_day['calendarDate'] = trading_day['calendarDate'].apply(lambda x: pd.to_datetime(x)) 101 | trading_day = trading_day[trading_day['isOpen'] == 1] 102 | trading_day.columns = [['DATE', 'OPEN']] 103 | trading_day.to_csv(config.TRAINING_DAY, index=False) 104 | 105 | def _update_quotation_data(): 106 | 107 | zz800_dataset = pd.read_csv(config.ZZ800_DATA, low_memory=False) 108 | new_zz800_data = _get_new_zz800_data(trading_day) 109 | 110 | codes = np.unique(np.hstack((new_zz800_data['CODE'].unique(), zz800_dataset['CODE'].unique()))) 111 | dates = trading_day['DATE'].values 112 | 113 | item = [] 114 | for code in codes: 115 | for date in dates: 116 | item.append([code, date]) 117 | dataset = pd.DataFrame(item, columns=['CODE', 'DATE']) 118 | 119 | update_dataset = dataset.merge(new_zz800_data, how='left', on=['CODE', 'DATE']) 120 | new_dataset = zz800_dataset.append(update_dataset) 121 | new_dataset = new_dataset.drop_duplicates(['CODE', 'DATE']) 122 | new_dataset = new_dataset.sort_values(ascending=True, by=['CODE', 'DATE']) 123 | return new_dataset 124 | 125 | def _update_RMVR_fft_data(new_dataset): 126 | date, _ = get_traiding_day(start=None, end=start) 127 | date = date.tail(30).head(1).values[0][0] 128 | 129 | df = new_dataset[new_dataset['DATE'] >= date] 130 | new_fft_dataset = init_800_RMVR_fft_data(df) 131 | 132 | new_fft_dataset = new_fft_dataset[new_fft_dataset['DATE'] >= start] 133 | 134 | fft_dataset = pd.read_csv(config.ZZ800_RM_VR_FFT, low_memory=False) 135 | new_fft_dataset = fft_dataset.append(new_fft_dataset) 136 | new_fft_dataset = new_fft_dataset.sort_values(ascending=True, by=['CODE', 'DATE']) 137 | new_fft_dataset = new_fft_dataset.drop_duplicates(['CODE', 'DATE']) 138 | return new_fft_dataset 139 | 140 | update_trading_date() 141 | trading_day, all_trading_day = get_traiding_day(start, end) 142 | if new_dataset is None: 143 | new_dataset = _update_quotation_data() 144 | zz800_fft_dataset = _update_RMVR_fft_data(new_dataset) 145 | 146 | return new_dataset, zz800_fft_dataset 147 | 148 | 149 | def init_dataset_matrix(): 150 | ''' 151 | 将 800_raw_data.csv 映射到 800_data.csv。 152 | 后者是一个按calendar day排列的字典,空值补Nan 153 | ''' 154 | 155 | zz800_raw_data = pd.read_csv(config.ZZ800_RAW_DATA, dtype={'SecuCode': str}) 156 | zz800_raw_data = zz800_raw_data[['SecuCode', 'date', 'ret', 'close']] 157 | zz800_raw_data.columns = ['CODE', 'DATE', 'RET', 'CLOSE'] 158 | 159 | zz800_raw_data = _format_code(zz800_raw_data) 160 | 161 | trading_day = pd.read_csv(config.TRAINING_DAY) 162 | trading_day = trading_day[(trading_day['DATE'] > '2007-01-01') & (trading_day['DATE'] < '2018-01-01')] 163 | 164 | def _mapping_to_dataset(): 165 | data = [] 166 | def apply(x): 167 | ret = trading_day.merge(x, on=['DATE'], how='left') 168 | ret['CODE'] = x['CODE'].values[0] 169 | data.append(ret) 170 | 171 | zz800_raw_data.groupby(['CODE']).apply(func=apply) 172 | dataset = pd.concat(data) 173 | 174 | index_ratio = pd.read_csv(config.MARKET_RATIO) 175 | dataset = dataset.drop_duplicates() 176 | dataset = dataset.merge(index_ratio, on=['DATE'], how='left') 177 | return dataset 178 | 179 | dataset = _mapping_to_dataset() 180 | dataset.to_csv(config.ZZ800_DATA, index=False) 181 | 182 | 183 | def init_800_RMVR_fft_data(input_data=None): 184 | print('init 800 remove-market-ratio fft data...') 185 | 186 | def apply(data, freq, method): 187 | result = data.copy() 188 | fft = [] 189 | for i in range(data.shape[0]): 190 | if i < 30: 191 | fft.append(None) 192 | else: 193 | ret = data['RET'].iloc[i - 30: i].values 194 | market = data['300_RATIO'].iloc[i - 30: i].values 195 | x_ = norm(ret, market) 196 | ffts = np.fft.fft(x_) / len(x_) 197 | if method == 'fft': 198 | fft.append(np.abs(ffts[freq])) 199 | elif method == 'deg': 200 | fft.append(np.rad2deg(np.angle(ffts[freq]))) 201 | 202 | result['RET'] = fft 203 | return result 204 | 205 | if input_data is None: 206 | data = pd.read_csv(config.ZZ800_DATA, low_memory=False) 207 | else: 208 | data = input_data 209 | 210 | for i in range(config.fft_level): 211 | ind = str(i+1) 212 | data.loc[:, 'fft' + ind] = data.groupby(['CODE'])[['CODE', '300_RATIO', 'RET']].apply(func=apply, freq=i, method='fft')['RET'].values 213 | data.loc[:, 'deg' + ind] = data.groupby(['CODE'])[['CODE', '300_RATIO', 'RET']].apply(func=apply, freq=i, method='deg')['RET'].values 214 | print('Calculating fft: ', ind) 215 | if input_data is None: 216 | data.to_csv(config.ZZ800_RM_VR_FFT, index=False) 217 | else: 218 | return data 219 | 220 | if __name__ == '__main__': 221 | 222 | # init_dataset_matrix() 223 | init_800_RMVR_fft_data() 224 | 225 | # start = config.update_start 226 | # end = config.update_end 227 | # 228 | # zz800_dataset, zz800_fft_dataset = update_data() 229 | # zz800_fft_dataset.to_csv(config.ZZ800_RM_VR_FFT, index=False) 230 | # zz800_dataset.to_csv(config.ZZ800_DATA, index=False) 231 | 232 | print('') 233 | -------------------------------------------------------------------------------- /codes/regression_test.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import numpy as np 4 | curPath = os.path.abspath(os.path.dirname(__file__)) 5 | rootPath = os.path.split(curPath)[0] 6 | sys.path.append(curPath) 7 | sys.path.append(rootPath) 8 | 9 | from codes.config import config 10 | if 'Youran/Projects/' in config.rootPath: 11 | print('Using Test Config!') 12 | config.nb_codes = 20 13 | config.cores = 4 14 | config.plot_simi_stock = False 15 | config.nb_similar_of_each_stock = 100 16 | config.nb_similar_make_prediction = 5 17 | config.nb_similar_of_all_similar = 15 18 | config.slide_window = 100 19 | 20 | import time 21 | import pandas as pd 22 | import matplotlib 23 | matplotlib.use('Agg') 24 | 25 | from multiprocessing import Pool 26 | from collections import OrderedDict 27 | from codes.search import predict_stock_base_on_similars, find_similar_of_a_stock 28 | from codes.market import market 29 | from scipy.stats.stats import pearsonr 30 | 31 | 32 | def make_index_prediction(): 33 | 34 | pool = Pool(processes=config.cores) 35 | all_stocks_avg_pred_results = pool.map(predict_stock_base_on_similars, market.codes) 36 | pool.close() 37 | 38 | pred1, pred5, pred10, pred20 = 0, 0, 0, 0 39 | for result in all_stocks_avg_pred_results: 40 | if result is None: 41 | continue 42 | pred1 += result[1] / len(all_stocks_avg_pred_results) 43 | pred5 += result[2] / len(all_stocks_avg_pred_results) 44 | pred10 += result[3] / len(all_stocks_avg_pred_results) 45 | pred20 += result[4] / len(all_stocks_avg_pred_results) 46 | 47 | m = market.get_data(start_date=market.current_date) 48 | act1 = (m['800_MARKET'].iloc[1] - m['800_MARKET'].iloc[0]) / m['800_MARKET'].iloc[0] 49 | act5 = (m['800_MARKET'].iloc[5] - m['800_MARKET'].iloc[0]) / m['800_MARKET'].iloc[0] 50 | act10 = (m['800_MARKET'].iloc[10] - m['800_MARKET'].iloc[0]) / m['800_MARKET'].iloc[0] 51 | act20 = (m['800_MARKET'].iloc[20] - m['800_MARKET'].iloc[0]) / m['800_MARKET'].iloc[0] 52 | 53 | 54 | # 汇总800*20支相似股票 55 | def make_prediction(): 56 | 57 | pool = Pool(processes=config.cores) 58 | all_stocks_avg_pred_results = pool.map(predict_stock_base_on_similars, market.codes) 59 | pool.close() 60 | all_stocks_avg_pred_results = [x for x in all_stocks_avg_pred_results if x is not None] 61 | 62 | pred_ratios1, pred_ratios5, pred_ratios10, pred_ratios20 = [], [], [], [] 63 | act_ratios1, act_ratios5, act_ratios10, act_ratios20, codes = [], [], [], [], [] 64 | 65 | for avg_pred_result in all_stocks_avg_pred_results: 66 | codes.append(avg_pred_result[0]) 67 | 68 | pred_ratios1.append(avg_pred_result[1]) 69 | pred_ratios5.append(avg_pred_result[2]) 70 | pred_ratios10.append(avg_pred_result[3]) 71 | pred_ratios20.append(avg_pred_result[4]) 72 | 73 | act = market.get_data(start_date=market.current_date, code=avg_pred_result[0]) 74 | 75 | if config.speed_method in ['rm_market_vr_fft']: 76 | act_market_ratios1 = market.get_span_market_ratio(act, 1) 77 | act_market_ratios5 = market.get_span_market_ratio(act, 5) 78 | act_market_ratios10 = market.get_span_market_ratio(act, 10) 79 | act_market_ratios20 = market.get_span_market_ratio(act, 20) 80 | else: 81 | act_market_ratios1, act_market_ratios5, act_market_ratios10, act_market_ratios20 = 0, 0, 0, 0 82 | 83 | act_ratios1.append((act.iloc[1]['CLOSE'] - act.iloc[0]['CLOSE']) / act.iloc[0]['CLOSE'] - act_market_ratios1) 84 | act_ratios5.append((act.iloc[5]['CLOSE'] - act.iloc[0]['CLOSE']) / act.iloc[0]['CLOSE'] - act_market_ratios5) 85 | act_ratios10.append((act.iloc[10]['CLOSE'] - act.iloc[0]['CLOSE']) / act.iloc[0]['CLOSE'] - act_market_ratios10) 86 | act_ratios20.append((act.iloc[20]['CLOSE'] - act.iloc[0]['CLOSE']) / act.iloc[0]['CLOSE'] - act_market_ratios20) 87 | 88 | preds = [pred_ratios1, pred_ratios5, pred_ratios10, pred_ratios20] 89 | acts = [act_ratios1, act_ratios5, act_ratios10, act_ratios20] 90 | 91 | get_prediction_and_calcu_corr(codes, preds, acts) 92 | 93 | 94 | # 先对每支股票的找200支相似,然后汇总800*200后取前4000 95 | def make_prediction2(): 96 | 97 | time_start = time.time() 98 | pool = Pool(processes=config.cores) 99 | tops = [] 100 | for codes in np.split(market.codes, min(20, os.cpu_count()), axis=0): 101 | result = pool.map(find_similar_of_a_stock, codes) 102 | tops = tops + result 103 | 104 | pool.close() 105 | time_end = time.time() 106 | print('Search Time:', time_end - time_start) 107 | 108 | print("---tops:", len(tops)) 109 | tops = [top for top in tops if top is not None and top.shape[0] != 0] 110 | print("---tops:", len(tops)) 111 | 112 | tops = pd.concat(tops).sort_values(ascending=True, by=[config.similarity_method]) 113 | tops.to_csv(config.rootPath + '/output/' + str(market.current_date.date()) + '_16K_similars.csv', index=False) 114 | 115 | tops = tops[tops[config.similarity_method] >= 0] 116 | tops = tops.head(config.nb_similar_of_all_similar) 117 | 118 | # tops.to_csv(config.rootPath + '/output/' + str(market.current_date.date()) + '_4K_similars.csv', index=False) 119 | 120 | print("---tops:", len(tops)) 121 | 122 | def apply(x): 123 | x_ = x.head(config.nb_similar_make_prediction).copy() 124 | pattern_code = x_['pattern'].values[0] 125 | 126 | pred_ratio1, pred_ratio2, pred_ratio3, pred_ratio4, pred_ratio5, pred_ratio10, pred_ratio20 = 0, 0, 0, 0, 0, 0, 0 127 | size = 0 128 | for index, top in x_.iterrows(): 129 | pred = market.get_data(start_date=top['DATE'], code=top['CODE']) 130 | 131 | if pred.shape[0] != 30: 132 | print('---Cannot found 30 ', top['CODE'], ' for ', pattern_code, ' start form ', str(top['DATE'])) 133 | continue 134 | size += 1 135 | pred_ratio1 += market.get_span_ret(pred, 1)/market.get_span_market_ratio(pred, 1) - 1 136 | pred_ratio2 += market.get_span_ret(pred, 2)/market.get_span_market_ratio(pred, 2) - 1 137 | pred_ratio3 += market.get_span_ret(pred, 3)/market.get_span_market_ratio(pred, 3) - 1 138 | pred_ratio4 += market.get_span_ret(pred, 4)/market.get_span_market_ratio(pred, 4) - 1 139 | pred_ratio5 += market.get_span_ret(pred, 5)/market.get_span_market_ratio(pred, 5) - 1 140 | pred_ratio10 += market.get_span_ret(pred, 10)/market.get_span_market_ratio(pred, 10) - 1 141 | pred_ratio20 += market.get_span_ret(pred, 20)/market.get_span_market_ratio(pred, 20) - 1 142 | 143 | if config.is_regression_test: 144 | act = market.get_data(start_date=market.current_date, code=pattern_code) 145 | act_ratios1.append(market.get_span_ret(act, 1)/market.get_span_market_ratio(act, 1) - 1) 146 | act_ratios2.append(market.get_span_ret(act, 2)/market.get_span_market_ratio(act, 2) - 1) 147 | act_ratios3.append(market.get_span_ret(act, 3)/market.get_span_market_ratio(act, 3) - 1) 148 | act_ratios4.append(market.get_span_ret(act, 4)/market.get_span_market_ratio(act, 4) - 1) 149 | act_ratios5.append(market.get_span_ret(act, 5)/market.get_span_market_ratio(act, 5) - 1) 150 | act_ratios10.append(market.get_span_ret(act, 10)/market.get_span_market_ratio(act, 10) - 1) 151 | act_ratios20.append(market.get_span_ret(act, 20)/market.get_span_market_ratio(act, 20) - 1) 152 | # else: 153 | # print('正在进行实际预测, 无实际值...', pattern_code) 154 | 155 | pred_ratios1.append(pred_ratio1 / size) 156 | pred_ratios2.append(pred_ratio2 / size) 157 | pred_ratios3.append(pred_ratio3 / size) 158 | pred_ratios4.append(pred_ratio4 / size) 159 | pred_ratios5.append(pred_ratio5 / size) 160 | pred_ratios10.append(pred_ratio10 / size) 161 | pred_ratios20.append(pred_ratio20 / size) 162 | 163 | codes.append(pattern_code) 164 | 165 | act_ratios1, act_ratios2, act_ratios3, act_ratios4, act_ratios5, act_ratios10, act_ratios20 = [], [], [], [], [], [], [] 166 | pred_ratios1, pred_ratios2, pred_ratios3, pred_ratios4, pred_ratios5, pred_ratios10, pred_ratios20 = [], [], [], [], [], [], [] 167 | codes = [] 168 | 169 | tops.groupby(['pattern']).apply(func=apply) 170 | print('[Codes left] ', len(codes)) 171 | 172 | preds = [pred_ratios1, pred_ratios2, pred_ratios3, pred_ratios4, pred_ratios5, pred_ratios10, pred_ratios20] 173 | acts = [act_ratios1, act_ratios2, act_ratios3, act_ratios4, act_ratios5, act_ratios10, act_ratios20] 174 | 175 | return get_prediction_and_calcu_corr(codes, preds, acts) if config.is_regression_test else get_prediction(codes, preds) 176 | 177 | 178 | def get_prediction_and_calcu_corr(codes, pred, act): 179 | 180 | pred_act_result = pd.DataFrame( 181 | OrderedDict({'CODE': codes, 'CURRENT_DATE': market.current_date, 'PRED1': pred[0], 182 | 'PRED2': pred[1], 'PRED3': pred[2], 'PRED4': pred[3], 183 | 'PRED5': pred[4], 'PRED10': pred[5], 'PRED20': pred[6], 184 | 'ACT1': act[0], 'ACT2': act[1], 'ACT3': act[2], 'ACT4': act[3], 185 | 'ACT5': act[4], 'ACT10': act[5], 'ACT20': act[6]})) 186 | pred_act_result = pred_act_result.dropna() 187 | path = config.rootPath + '/output/pred_' + str(market.current_date.date()) + '.csv' 188 | pred_act_result.to_csv(path, index=False) 189 | 190 | p1 = pearsonr(pred[0], act[0])[0] 191 | p2 = pearsonr(pred[1], act[1])[0] 192 | p3 = pearsonr(pred[2], act[2])[0] 193 | p4 = pearsonr(pred[3], act[3])[0] 194 | p5 = pearsonr(pred[4], act[4])[0] 195 | p10 = pearsonr(pred[5], act[5])[0] 196 | p20 = pearsonr(pred[6], act[6])[0] 197 | 198 | pearson = pd.DataFrame( 199 | OrderedDict({'CURRENT_DATE': [market.current_date], 200 | 'P1': [p1], 'P2': [p2], 'P3': [p3], 'P4': [p4], 201 | 'P4': [p5], 'P10': [p10], 'P20': [p20]})) 202 | pearson.to_csv(config.PEARSON_CORR_RESLUT, mode='a', header=False, index=False) 203 | 204 | print('[Correlation1] ', p1) 205 | print('[Correlation2] ', p2) 206 | print('[Correlation3] ', p3) 207 | print('[Correlation4] ', p4) 208 | print('[Correlation5] ', p5) 209 | print('[Correlation10] ', p10) 210 | print('[Correlation20] ', p20) 211 | 212 | 213 | def get_prediction(codes, pred): 214 | pred_result = pd.DataFrame(OrderedDict({'CODE': codes, 'CURRENT_DATE': market.current_date, 215 | 'PRED1': pred[0], 'PRED2': pred[1], 'PRED3': pred[2], 216 | 'PRED4': pred[3], 'PRED5': pred[4], 'PRED10': pred[5], 217 | 'PRED20': pred[6]})) 218 | 219 | pred_result = pred_result.dropna() 220 | pred_result = pred_result.sort_values(ascending=False, by=['PRED5']) 221 | 222 | path = config.rootPath + '/output/pred_' + str(market.current_date.date()) + '.csv' 223 | pred_result.to_csv(path, index=False) 224 | 225 | 226 | if __name__ == '__main__': 227 | 228 | time_start = time.time() 229 | 230 | print('\n#####################################') 231 | print('Cpu Core Num: ', os.cpu_count()) 232 | print('Cpu Core Ocp: ', config.cores) 233 | print('Start Date: ' + str(config.start_date)) 234 | print('Codes NB: ' + str(config.nb_codes)) 235 | print('Similar NB: ' + str(config.nb_similar_make_prediction)) 236 | print('#####################################') 237 | 238 | while config.start_date <= config.regression_end_date: 239 | print('\n[Current Date]: ' + str(market.current_date.date())) 240 | make_prediction2() 241 | # make_prediction() 242 | # make_index_prediction() 243 | 244 | if config.is_regression_test: 245 | market._pass_a_week() 246 | else: 247 | market._pass_a_day() 248 | 249 | time_end = time.time() 250 | print('Total Search Time:', time_end - time_start) -------------------------------------------------------------------------------- /test/test.csv: -------------------------------------------------------------------------------- 1 | CODE,DATE,CLOSE 2 | 603883.SH,2015/11/20,55.5 3 | 603883.SH,2015/11/23,61.05 4 | 603883.SH,2015/11/24,67.16 5 | 603883.SH,2015/11/25,73.88 6 | 603883.SH,2015/11/26,81.27 7 | 603883.SH,2015/11/27,75.35 8 | 603883.SH,2015/11/30,75.88 9 | 603883.SH,2015/12/1,71.57 10 | 603883.SH,2015/12/2,72.56 11 | 603883.SH,2015/12/3,73.26 12 | 603883.SH,2015/12/4,73.0 13 | 603883.SH,2015/12/7,71.79 14 | 603883.SH,2015/12/8,69.02 15 | 603883.SH,2015/12/9,69.47 16 | 603883.SH,2015/12/10,67.81 17 | 603883.SH,2015/12/11,68.91 18 | 603883.SH,2015/12/14,69.25 19 | 603883.SH,2015/12/15,68.92 20 | 603883.SH,2015/12/16,69.58 21 | 603883.SH,2015/12/17,73.16 22 | 603883.SH,2015/12/18,70.66 23 | 603883.SH,2015/12/21,69.8 24 | 603883.SH,2015/12/22,69.58 25 | 603883.SH,2015/12/23,68.66 26 | 603883.SH,2015/12/24,70.62 27 | 603883.SH,2015/12/25,71.1 28 | 603883.SH,2015/12/28,72.42 29 | 603883.SH,2015/12/29,73.62 30 | 603883.SH,2015/12/30,73.39 31 | 603883.SH,2015/12/31,70.97 32 | 603883.SH,2016/1/4,63.87 33 | 603883.SH,2016/1/5,60.0 34 | 603883.SH,2016/1/6,63.21 35 | 603883.SH,2016/1/7,56.89 36 | 603883.SH,2016/1/8,57.59 37 | 603883.SH,2016/1/11,51.83 38 | 603883.SH,2016/1/12,53.16 39 | 603883.SH,2016/1/13,50.53 40 | 603883.SH,2016/1/14,51.54 41 | 603883.SH,2016/1/15,48.41 42 | 603883.SH,2016/1/18,50.51 43 | 603883.SH,2016/1/19,53.45 44 | 603883.SH,2016/1/20,53.01 45 | 603883.SH,2016/1/21,50.17 46 | 603883.SH,2016/1/22,50.98 47 | 603883.SH,2016/1/25,51.0 48 | 603883.SH,2016/1/26,45.91 49 | 603883.SH,2016/1/27,46.01 50 | 603883.SH,2016/1/28,42.98 51 | 603883.SH,2016/1/29,45.2 52 | 603883.SH,2016/2/1,45.41 53 | 603883.SH,2016/2/2,47.22 54 | 603883.SH,2016/2/3,47.09 55 | 603883.SH,2016/2/4,48.25 56 | 603883.SH,2016/2/5,48.92 57 | 603883.SH,2016/2/15,48.91 58 | 603883.SH,2016/2/16,50.36 59 | 603883.SH,2016/2/17,50.08 60 | 603883.SH,2016/2/18,48.4 61 | 603883.SH,2016/2/19,48.93 62 | 603883.SH,2016/2/22,50.77 63 | 603883.SH,2016/2/23,49.88 64 | 603883.SH,2016/2/24,49.05 65 | 603883.SH,2016/2/25,44.41 66 | 603883.SH,2016/2/26,43.76 67 | 603883.SH,2016/2/29,40.88 68 | 603883.SH,2016/3/1,41.74 69 | 603883.SH,2016/3/2,43.41 70 | 603883.SH,2016/3/3,42.82 71 | 603883.SH,2016/3/4,40.31 72 | 603883.SH,2016/3/7,41.34 73 | 603883.SH,2016/3/8,41.37 74 | 603883.SH,2016/3/9,40.79 75 | 603883.SH,2016/3/10,40.41 76 | 603883.SH,2016/3/11,41.05 77 | 603883.SH,2016/3/14,42.31 78 | 603883.SH,2016/3/15,41.64 79 | 603883.SH,2016/3/16,40.97 80 | 603883.SH,2016/3/17,42.38 81 | 603883.SH,2016/3/18,45.99 82 | 603883.SH,2016/3/21,46.36 83 | 603883.SH,2016/3/22,46.12 84 | 603883.SH,2016/3/23,48.09 85 | 603883.SH,2016/3/24,49.09 86 | 603883.SH,2016/3/25,46.33 87 | 603883.SH,2016/3/28,45.12 88 | 603883.SH,2016/3/29,44.05 89 | 603883.SH,2016/3/30,45.69 90 | 603883.SH,2016/3/31,45.52 91 | 603883.SH,2016/4/1,44.81 92 | 603883.SH,2016/4/5,46.0 93 | 603883.SH,2016/4/6,46.14 94 | 603883.SH,2016/4/7,47.46 95 | 603883.SH,2016/4/8,52.21 96 | 603883.SH,2016/4/11,54.89 97 | 603883.SH,2016/4/12,52.01 98 | 603883.SH,2016/4/13,52.01 99 | 603883.SH,2016/4/14,52.23 100 | 603883.SH,2016/4/15,51.58 101 | 603883.SH,2016/4/18,50.2 102 | 603883.SH,2016/4/19,53.03 103 | 603883.SH,2016/4/20,49.08 104 | 603883.SH,2016/4/21,47.98 105 | 603883.SH,2016/4/22,48.54 106 | 603883.SH,2016/4/25,47.92 107 | 603883.SH,2016/4/26,48.84 108 | 603883.SH,2016/4/27,48.57 109 | 603883.SH,2016/4/28,47.77 110 | 603883.SH,2016/4/29,47.27 111 | 603883.SH,2016/5/3,48.82 112 | 603883.SH,2016/5/4,50.96 113 | 603883.SH,2016/5/5,50.43 114 | 603883.SH,2016/5/6,48.06 115 | 603883.SH,2016/5/9,47.07 116 | 603883.SH,2016/5/10,47.28 117 | 603883.SH,2016/5/11,47.84 118 | 603883.SH,2016/5/12,47.38 119 | 603883.SH,2016/5/13,47.12 120 | 603883.SH,2016/5/16,47.69 121 | 603883.SH,2016/5/17,48.22 122 | 603883.SH,2016/5/18,46.34 123 | 603883.SH,2016/5/19,46.35 124 | 603883.SH,2016/5/20,46.19 125 | 603883.SH,2016/5/23,46.74 126 | 603883.SH,2016/5/24,46.9 127 | 603883.SH,2016/5/25,46.44 128 | 603883.SH,2016/5/26,45.88 129 | 603883.SH,2016/5/27,45.57 130 | 603883.SH,2016/5/30,45.2 131 | 603883.SH,2016/5/31,47.06 132 | 603883.SH,2016/6/1,48.25 133 | 603883.SH,2016/6/2,48.91 134 | 603883.SH,2016/6/3,48.9 135 | 603883.SH,2016/6/6,48.51 136 | 603883.SH,2016/6/7,48.84 137 | 603883.SH,2016/6/8,48.25 138 | 603883.SH,2016/6/13,45.07 139 | 603883.SH,2016/6/14,45.06 140 | 603883.SH,2016/6/15,46.1 141 | 603883.SH,2016/6/16,45.49 142 | 603883.SH,2016/6/17,45.91 143 | 603883.SH,2016/6/20,47.6 144 | 603883.SH,2016/6/21,46.75 145 | 603883.SH,2016/6/22,47.35 146 | 603883.SH,2016/6/23,47.6 147 | 603883.SH,2016/6/24,46.45 148 | 603883.SH,2016/6/27,48.43 149 | 603883.SH,2016/6/28,49.57 150 | 603883.SH,2016/6/29,49.63 151 | 603883.SH,2016/6/30,49.74 152 | 603883.SH,2016/7/1,49.31 153 | 603883.SH,2016/7/4,50.46 154 | 603883.SH,2016/7/5,49.8 155 | 603883.SH,2016/7/6,50.79 156 | 603883.SH,2016/7/7,50.39 157 | 603883.SH,2016/7/8,50.65 158 | 603883.SH,2016/7/11,53.9 159 | 603883.SH,2016/7/12,55.44 160 | 603883.SH,2016/7/13,54.42 161 | 603883.SH,2016/7/14,53.57 162 | 603883.SH,2016/7/15,51.66 163 | 603883.SH,2016/7/18,51.55 164 | 603883.SH,2016/7/19,51.62 165 | 603883.SH,2016/7/20,51.51 166 | 603883.SH,2016/7/21,51.11 167 | 603883.SH,2016/7/22,49.66 168 | 603883.SH,2016/7/25,50.11 169 | 603883.SH,2016/7/26,51.23 170 | 603883.SH,2016/7/27,48.95 171 | 603883.SH,2016/7/28,49.5 172 | 603883.SH,2016/7/29,49.69 173 | 603883.SH,2016/8/1,48.59 174 | 603883.SH,2016/8/2,50.12 175 | 603883.SH,2016/8/3,49.96 176 | 603883.SH,2016/8/4,49.88 177 | 603883.SH,2016/8/5,49.18 178 | 603883.SH,2016/8/8,49.42 179 | 603883.SH,2016/8/9,49.85 180 | 603883.SH,2016/8/10,49.55 181 | 603883.SH,2016/8/11,48.4 182 | 603883.SH,2016/8/12,48.65 183 | 603883.SH,2016/8/15,49.95 184 | 603883.SH,2016/8/16,50.32 185 | 603883.SH,2016/8/17,50.32 186 | 603883.SH,2016/8/18,50.32 187 | 603883.SH,2016/8/19,50.32 188 | 603883.SH,2016/8/22,50.32 189 | 603883.SH,2016/8/23,50.32 190 | 603883.SH,2016/8/24,50.32 191 | 603883.SH,2016/8/25,50.32 192 | 603883.SH,2016/8/26,50.32 193 | 603883.SH,2016/8/29,50.32 194 | 603883.SH,2016/8/30,50.32 195 | 603883.SH,2016/8/31,50.32 196 | 603883.SH,2016/9/1,50.32 197 | 603883.SH,2016/9/2,50.32 198 | 603883.SH,2016/9/5,50.32 199 | 603883.SH,2016/9/6,50.32 200 | 603883.SH,2016/9/7,50.32 201 | 603883.SH,2016/9/8,50.32 202 | 603883.SH,2016/9/9,50.32 203 | 603883.SH,2016/9/12,50.32 204 | 603883.SH,2016/9/13,50.32 205 | 603883.SH,2016/9/14,50.32 206 | 603883.SH,2016/9/19,50.32 207 | 603883.SH,2016/9/20,50.32 208 | 603883.SH,2016/9/21,50.32 209 | 603883.SH,2016/9/22,50.32 210 | 603883.SH,2016/9/23,50.32 211 | 603883.SH,2016/9/26,50.32 212 | 603883.SH,2016/9/27,50.32 213 | 603883.SH,2016/9/28,50.32 214 | 603883.SH,2016/9/29,50.32 215 | 603883.SH,2016/9/30,50.32 216 | 603883.SH,2016/10/10,50.32 217 | 603883.SH,2016/10/11,50.32 218 | 603883.SH,2016/10/12,50.32 219 | 603883.SH,2016/10/13,50.32 220 | 603883.SH,2016/10/14,50.32 221 | 603883.SH,2016/10/17,50.32 222 | 603883.SH,2016/10/18,51.8 223 | 603883.SH,2016/10/19,50.86 224 | 603883.SH,2016/10/20,50.22 225 | 603883.SH,2016/10/21,49.67 226 | 603883.SH,2016/10/24,49.75 227 | 603883.SH,2016/10/25,49.2 228 | 603883.SH,2016/10/26,49.96 229 | 603883.SH,2016/10/27,49.54 230 | 603883.SH,2016/10/28,49.32 231 | 603883.SH,2016/10/31,50.99 232 | 603883.SH,2016/11/1,51.46 233 | 603883.SH,2016/11/2,50.46 234 | 603883.SH,2016/11/3,50.77 235 | 603883.SH,2016/11/4,51.77 236 | 603883.SH,2016/11/7,51.53 237 | 603883.SH,2016/11/8,51.45 238 | 603883.SH,2016/11/9,50.33 239 | 603883.SH,2016/11/10,51.92 240 | 603883.SH,2016/11/11,52.08 241 | 603883.SH,2016/11/14,52.12 242 | 603883.SH,2016/11/15,51.89 243 | 603883.SH,2016/11/16,52.39 244 | 603883.SH,2016/11/17,51.45 245 | 603883.SH,2016/11/18,52.97 246 | 603883.SH,2016/11/21,54.16 247 | 603883.SH,2016/11/22,53.94 248 | 603883.SH,2016/11/23,52.95 249 | 603883.SH,2016/11/24,52.39 250 | 603883.SH,2016/11/25,52.18 251 | 603883.SH,2016/11/28,51.76 252 | 603883.SH,2016/11/29,51.49 253 | 603883.SH,2016/11/30,51.6 254 | 603883.SH,2016/12/1,51.82 255 | 603883.SH,2016/12/2,49.63 256 | 603883.SH,2016/12/5,49.76 257 | 603883.SH,2016/12/6,49.61 258 | 603883.SH,2016/12/7,50.08 259 | 603883.SH,2016/12/8,49.68 260 | 603883.SH,2016/12/9,49.43 261 | 603883.SH,2016/12/12,46.99 262 | 603883.SH,2016/12/13,47.15 263 | 603883.SH,2016/12/14,46.51 264 | 603883.SH,2016/12/15,46.8 265 | 603883.SH,2016/12/16,47.03 266 | 603883.SH,2016/12/19,46.89 267 | 603883.SH,2016/12/20,46.77 268 | 603883.SH,2016/12/21,47.23 269 | 603883.SH,2016/12/22,47.25 270 | 603883.SH,2016/12/23,46.39 271 | 603883.SH,2016/12/26,46.76 272 | 603883.SH,2016/12/27,46.78 273 | 603883.SH,2016/12/28,46.74 274 | 603883.SH,2016/12/29,46.43 275 | 603883.SH,2016/12/30,46.65 276 | 603883.SH,2017/1/3,47.14 277 | 603883.SH,2017/1/4,47.32 278 | 603883.SH,2017/1/5,47.14 279 | 603883.SH,2017/1/6,46.33 280 | 603883.SH,2017/1/9,47.09 281 | 603883.SH,2017/1/10,47.15 282 | 603883.SH,2017/1/11,47.49 283 | 603883.SH,2017/1/12,46.57 284 | 603883.SH,2017/1/13,44.83 285 | 603883.SH,2017/1/16,43.29 286 | 603883.SH,2017/1/17,43.75 287 | 603883.SH,2017/1/18,43.67 288 | 603883.SH,2017/1/19,43.49 289 | 603883.SH,2017/1/20,44.42 290 | 603883.SH,2017/1/23,44.39 291 | 603883.SH,2017/1/24,43.74 292 | 603883.SH,2017/1/25,44.05 293 | 603883.SH,2017/1/26,44.14 294 | 603883.SH,2017/2/3,44.02 295 | 603883.SH,2017/2/6,44.45 296 | 603883.SH,2017/2/7,44.22 297 | 603883.SH,2017/2/8,44.48 298 | 603883.SH,2017/2/9,45.01 299 | 603883.SH,2017/2/10,44.9 300 | 603883.SH,2017/2/13,44.95 301 | 603883.SH,2017/2/14,46.06 302 | 603883.SH,2017/2/15,45.03 303 | 603883.SH,2017/2/16,45.4 304 | 603883.SH,2017/2/17,44.03 305 | 603883.SH,2017/2/20,44.26 306 | 603883.SH,2017/2/21,44.87 307 | 603883.SH,2017/2/22,44.89 308 | 603883.SH,2017/2/23,45.47 309 | 603883.SH,2017/2/24,45.39 310 | 603883.SH,2017/2/27,45.45 311 | 603883.SH,2017/2/28,45.35 312 | 603883.SH,2017/3/1,45.34 313 | 603883.SH,2017/3/2,44.85 314 | 603883.SH,2017/3/3,44.69 315 | 603883.SH,2017/3/6,45.29 316 | 603883.SH,2017/3/7,45.48 317 | 603883.SH,2017/3/8,45.17 318 | 603883.SH,2017/3/9,45.18 319 | 603883.SH,2017/3/10,45.29 320 | 603883.SH,2017/3/13,45.45 321 | 603883.SH,2017/3/14,45.52 322 | 603883.SH,2017/3/15,45.53 323 | 603883.SH,2017/3/16,46.01 324 | 603883.SH,2017/3/17,46.3 325 | 603883.SH,2017/3/20,46.81 326 | 603883.SH,2017/3/21,46.84 327 | 603883.SH,2017/3/22,46.96 328 | 603883.SH,2017/3/23,47.23 329 | 603883.SH,2017/3/24,45.87 330 | 603883.SH,2017/3/27,45.41 331 | 603883.SH,2017/3/28,43.79 332 | 603883.SH,2017/3/29,42.91 333 | 603883.SH,2017/3/30,43.5 334 | 603883.SH,2017/3/31,43.99 335 | 603883.SH,2017/4/5,44.03 336 | 603883.SH,2017/4/6,44.07 337 | 603883.SH,2017/4/7,43.58 338 | 603883.SH,2017/4/10,43.06 339 | 603883.SH,2017/4/11,43.11 340 | 603883.SH,2017/4/12,42.64 341 | 603883.SH,2017/4/13,42.65 342 | 603883.SH,2017/4/14,42.16 343 | 603883.SH,2017/4/17,41.29 344 | 603883.SH,2017/4/18,41.62 345 | 603883.SH,2017/4/19,41.37 346 | 603883.SH,2017/4/20,42.47 347 | 603883.SH,2017/4/21,41.97 348 | 603883.SH,2017/4/24,41.95 349 | 603883.SH,2017/4/25,42.93 350 | 603883.SH,2017/4/26,43.67 351 | 603883.SH,2017/4/27,43.9 352 | 603883.SH,2017/4/28,43.71 353 | 603883.SH,2017/5/2,43.28 354 | 603883.SH,2017/5/3,43.29 355 | 603883.SH,2017/5/4,44.08 356 | 603883.SH,2017/5/5,43.95 357 | 603883.SH,2017/5/8,43.16 358 | 603883.SH,2017/5/9,43.47 359 | 603883.SH,2017/5/10,42.15 360 | 603883.SH,2017/5/11,42.43 361 | 603883.SH,2017/5/12,42.17 362 | 603883.SH,2017/5/15,42.58 363 | 603883.SH,2017/5/16,43.54 364 | 603883.SH,2017/5/17,44.13 365 | 603883.SH,2017/5/18,43.7 366 | 603883.SH,2017/5/19,43.84 367 | 603883.SH,2017/5/22,43.32 368 | 603883.SH,2017/5/23,43.81 369 | 603883.SH,2017/5/24,43.81 370 | 603883.SH,2017/5/25,44.43 371 | 603883.SH,2017/5/26,44.32 372 | 603883.SH,2017/5/31,44.64 373 | 603883.SH,2017/6/1,44.43 374 | 603883.SH,2017/6/2,44.84 375 | 603883.SH,2017/6/5,44.35 376 | 603883.SH,2017/6/6,45.11 377 | 603883.SH,2017/6/7,45.75 378 | 603883.SH,2017/6/8,45.75 379 | 603883.SH,2017/6/9,45.7 380 | 603883.SH,2017/6/12,47.09 381 | 603883.SH,2017/6/13,47.35 382 | 603883.SH,2017/6/14,47.71 383 | 603883.SH,2017/6/15,47.54 384 | 603883.SH,2017/6/16,47.3 385 | 603883.SH,2017/6/19,47.87 386 | 603883.SH,2017/6/20,47.28 387 | 603883.SH,2017/6/21,46.47 388 | 603883.SH,2017/6/22,45.67 389 | 603883.SH,2017/6/23,46.35 390 | 603883.SH,2017/6/26,47.25 391 | 603883.SH,2017/6/27,47.23 392 | 603883.SH,2017/6/28,47.73 393 | 603883.SH,2017/6/29,47.52 394 | 603883.SH,2017/6/30,48.65 395 | 603883.SH,2017/7/3,48.58 396 | 603883.SH,2017/7/4,47.54 397 | 603883.SH,2017/7/5,47.8 398 | 603883.SH,2017/7/6,48.05 399 | 603883.SH,2017/7/7,46.96 400 | 603883.SH,2017/7/10,45.98 401 | 603883.SH,2017/7/11,46.58 402 | 603883.SH,2017/7/12,46.1 403 | 603883.SH,2017/7/13,46.14 404 | 603883.SH,2017/7/14,45.77 405 | 603883.SH,2017/7/17,45.51 406 | 603883.SH,2017/7/18,44.45 407 | 603883.SH,2017/7/19,44.7 408 | 603883.SH,2017/7/20,44.76 409 | 603883.SH,2017/7/21,44.62 410 | 603883.SH,2017/7/24,45.78 411 | 603883.SH,2017/7/25,45.42 412 | 603883.SH,2017/7/26,45.12 413 | 603883.SH,2017/7/27,45.91 414 | 603883.SH,2017/7/28,46.24 415 | 603883.SH,2017/7/31,46.31 416 | 603883.SH,2017/8/1,45.69 417 | 603883.SH,2017/8/2,46.14 418 | 603883.SH,2017/8/3,46.72 419 | 603883.SH,2017/8/4,46.93 420 | 603883.SH,2017/8/7,46.83 421 | 603883.SH,2017/8/8,46.29 422 | 603883.SH,2017/8/9,46.34 423 | 603883.SH,2017/8/10,45.36 424 | 603883.SH,2017/8/11,45.67 425 | 603883.SH,2017/8/14,46.35 426 | 603883.SH,2017/8/15,46.62 427 | 603883.SH,2017/8/16,46.45 428 | 603883.SH,2017/8/17,47.06 429 | 603883.SH,2017/8/18,47.95 430 | 603883.SH,2017/8/21,48.32 431 | 603883.SH,2017/8/22,47.97 432 | 603883.SH,2017/8/23,47.94 433 | 603883.SH,2017/8/24,48.2 434 | 603883.SH,2017/8/25,48.31 435 | 603883.SH,2017/8/28,48.65 436 | 603883.SH,2017/8/29,48.79 437 | 603883.SH,2017/8/30,51.25 438 | 603883.SH,2017/8/31,50.37 439 | 603883.SH,2017/9/1,50.95 440 | 603883.SH,2017/9/4,50.37 441 | 603883.SH,2017/9/5,50.52 442 | 603883.SH,2017/9/6,50.23 443 | 603883.SH,2017/9/7,49.82 444 | 603883.SH,2017/9/8,49.81 445 | 603883.SH,2017/9/11,50.24 446 | 603883.SH,2017/9/12,50.16 447 | 603883.SH,2017/9/13,49.87 448 | 603883.SH,2017/9/14,49.04 449 | 603883.SH,2017/9/15,50.11 450 | 603883.SH,2017/9/18,49.81 451 | 603883.SH,2017/9/19,49.34 452 | 603883.SH,2017/9/20,50.43 453 | 603883.SH,2017/9/21,49.49 454 | 603883.SH,2017/9/22,48.78 455 | 603883.SH,2017/9/25,48.42 456 | 603883.SH,2017/9/26,47.84 457 | 603883.SH,2017/9/27,47.89 458 | 603883.SH,2017/9/28,47.65 459 | 603883.SH,2017/9/29,48.71 460 | 603883.SH,2017/10/9,48.77 461 | 603883.SH,2017/10/10,50.39 462 | 603883.SH,2017/10/11,50.0 463 | 603883.SH,2017/10/12,50.99 464 | 603883.SH,2017/10/13,50.91 465 | 603883.SH,2017/10/16,49.95 466 | 603883.SH,2017/10/17,50.51 467 | 603883.SH,2017/10/18,50.03 468 | 603883.SH,2017/10/19,50.02 469 | 603883.SH,2017/10/20,50.12 470 | 603883.SH,2017/10/23,52.08 471 | 603883.SH,2017/10/24,52.83 472 | 603883.SH,2017/10/25,53.04 473 | 603883.SH,2017/10/26,53.54 474 | 603883.SH,2017/10/27,54.11 475 | 603883.SH,2017/10/30,55.4 476 | 603883.SH,2017/10/31,56.05 477 | 603883.SH,2017/11/1,57.97 478 | 603883.SH,2017/11/2,56.9 479 | 603883.SH,2017/11/3,57.4 480 | 603883.SH,2017/11/6,59.03 481 | 603883.SH,2017/11/7,58.37 482 | 603883.SH,2017/11/8,58.44 483 | 603883.SH,2017/11/9,59.38 484 | 603883.SH,2017/11/10,58.99 485 | 603883.SH,2017/11/13,62.92 486 | 603883.SH,2017/11/14,62.08 487 | 603883.SH,2017/11/15,59.2 488 | 603883.SH,2017/11/16,61.18 489 | 603883.SH,2017/11/17,58.88 490 | 603883.SH,2017/11/20,60.22 491 | 603883.SH,2017/11/21,62.09 492 | 603883.SH,2017/11/22,59.83 493 | 603883.SH,2017/11/23,55.56 494 | 603883.SH,2017/11/24,57.1 495 | 603883.SH,2017/11/27,57.05 496 | 603883.SH,2017/11/28,58.13 497 | 603883.SH,2017/11/29,56.43 498 | 603883.SH,2017/11/30,58.6 499 | 603883.SH,2017/12/1,57.91 500 | 603883.SH,2017/12/4,57.5 501 | 603883.SH,2017/12/5,57.89 502 | 603883.SH,2017/12/6,57.91 503 | 603883.SH,2017/12/7,58.77 504 | 603883.SH,2017/12/8,58.11 505 | 603883.SH,2017/12/11,57.81 506 | 603883.SH,2017/12/12,55.91 507 | 603883.SH,2017/12/13,56.68 508 | 603883.SH,2017/12/14,59.88 509 | 603883.SH,2017/12/15,59.74 510 | 603883.SH,2017/12/18,61.85 511 | 603883.SH,2017/12/19,61.87 512 | 603883.SH,2017/12/20,61.19 513 | 603883.SH,2017/12/21,61.83 514 | 603883.SH,2017/12/22,61.03 515 | 603883.SH,2017/12/25,61.6 516 | 603883.SH,2017/12/26,63.99 517 | 603883.SH,2017/12/27,61.69 518 | 603883.SH,2017/12/28,60.9 519 | 603883.SH,2017/12/29,62.99 520 | --------------------------------------------------------------------------------