Unverified Commit 3e1adcd1 authored by Dr.李's avatar Dr.李 Committed by GitHub

Merge pull request #11 from iLampard/master

Add Tensorflow notebook example
parents 20cc62c1 8c83fcda
...@@ -176,7 +176,10 @@ def batch_processing(names, ...@@ -176,7 +176,10 @@ def batch_processing(names,
inner_left_index = bisect.bisect_left(sub_dates, end) inner_left_index = bisect.bisect_left(sub_dates, end)
inner_right_index = bisect.bisect_right(sub_dates, end) inner_right_index = bisect.bisect_right(sub_dates, end)
predict_x_buckets[end] = pd.DataFrame(ne_x[inner_left_index:inner_right_index], columns=names) predict_x_buckets[end] = pd.DataFrame(ne_x[inner_left_index:inner_right_index], columns=names)
predict_risk_buckets[end] = this_risk_exp[inner_left_index:inner_right_index] if risk_exp is not None:
predict_risk_buckets[end] = this_risk_exp[inner_left_index:inner_right_index]
else:
predict_risk_buckets = None
predict_codes_bucket[end] = this_codes[inner_left_index:inner_right_index] predict_codes_bucket[end] = this_codes[inner_left_index:inner_right_index]
this_raw_y = y_values[left_index:right_index] this_raw_y = y_values[left_index:right_index]
...@@ -262,7 +265,10 @@ def fetch_data_package(engine: SqlEngine, ...@@ -262,7 +265,10 @@ def fetch_data_package(engine: SqlEngine,
predict_x_buckets = {k: predict_x_buckets[k] for k in predict_x_buckets if k.strftime('%Y-%m-%d') >= start_date} predict_x_buckets = {k: predict_x_buckets[k] for k in predict_x_buckets if k.strftime('%Y-%m-%d') >= start_date}
predict_y_buckets = {k: predict_y_buckets[k] for k in predict_y_buckets if k.strftime('%Y-%m-%d') >= start_date} predict_y_buckets = {k: predict_y_buckets[k] for k in predict_y_buckets if k.strftime('%Y-%m-%d') >= start_date}
predict_risk_buckets = {k: predict_risk_buckets[k] for k in predict_risk_buckets if k.strftime('%Y-%m-%d') >= start_date} if neutralized_risk:
predict_risk_buckets = {k: predict_risk_buckets[k] for k in predict_risk_buckets if k.strftime('%Y-%m-%d') >= start_date}
else:
predict_risk_buckets = None
predict_codes_bucket = {k: predict_codes_bucket[k] for k in predict_codes_bucket if k.strftime('%Y-%m-%d') >= start_date} predict_codes_bucket = {k: predict_codes_bucket[k] for k in predict_codes_bucket if k.strftime('%Y-%m-%d') >= start_date}
ret['train'] = {'x': train_x_buckets, 'y': train_y_buckets, 'risk': train_risk_buckets} ret['train'] = {'x': train_x_buckets, 'y': train_y_buckets, 'risk': train_risk_buckets}
......
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* 本例展示如何在alpha-mind中使用深度学习模型。\n",
" - 为方便比较,使用的数据参数与[机器学习模型示例](https://github.com/alpha-miner/alpha-mind/blob/master/notebooks/Example%2012%20-%20Machine%20Learning%20Model%20Prediction.ipynb)一致。\n",
" - 本例以tensorflow实现深度学习模型,故需要预装tensorflow。\n",
"\n",
"* 请在环境变量中设置`DB_URI`指向数据库"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"E:\\workarea\\software\\conda3\\lib\\site-packages\\h5py\\__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.\n",
" from ._conv import register_converters as _register_converters\n"
]
}
],
"source": [
"%matplotlib inline\n",
"\n",
"import os\n",
"import datetime as dt\n",
"import numpy as np\n",
"import pandas as pd\n",
"from alphamind.api import *\n",
"from PyFin.api import *\n",
"import tensorflow as tf\n",
"from alphamind.model.modelbase import create_model_base"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 使用Tensorflow构建模型(以线性回归为例)\n",
"\n",
"### 构建Tensorflow的接口模型\n",
"\n",
"- alpha-mind中所有的模型算法都是通过底层接口模型实现的。在接口模型中都有统一的训练与预测方法,即*fit* 和 *predict*。\n",
"- 下面的代码就是创建一个接口类,使用tensorflow实现线性回归的算法。*fit* 和 *predict* 分别对应拟合与预测功能。"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"class LinearRegressionImpl(object):\n",
" def __init__(self, **kwargs):\n",
" self.learning_rate = kwargs.get('learning_rate', 0.01)\n",
" self.training_epochs = kwargs.get('training_epochs', 10)\n",
" self.display_steps = kwargs.get('display_steps', None)\n",
" self.W = None\n",
" self.b = None\n",
"\n",
" def result(self):\n",
" with tf.Session() as sess:\n",
" ret = [sess.run(self.W), sess.run(self.b)]\n",
" return ret\n",
"\n",
" def fit(self, x, y):\n",
" num_samples, num_features = x.shape\n",
"\n",
" X = tf.placeholder(\"float\", shape=[None, num_features])\n",
" Y = tf.placeholder(\"float\", shape=[None, 1])\n",
" W = tf.Variable(np.random.randn(num_features, 1).astype(np.float32), name=\"weight\")\n",
" b = tf.Variable(np.random.randn(), name=\"bias\")\n",
" pred = tf.add(tf.matmul(X, W), b)\n",
"\n",
" # Mean squared error\n",
" cost = tf.reduce_sum(tf.pow(pred - Y, 2)) / (2 * num_samples)\n",
" # Gradient descent\n",
" optimizer = tf.train.GradientDescentOptimizer(self.learning_rate).minimize(cost)\n",
"\n",
" with tf.Session() as sess:\n",
" sess.run(tf.global_variables_initializer())\n",
"\n",
" for epoch in range(self.training_epochs):\n",
" for (train_x, train_y) in zip(x, y):\n",
" sess.run(optimizer, feed_dict={X: train_x.reshape(1, -1), Y: train_y.reshape(1, -1)})\n",
"\n",
" if self.display_steps is not None and (epoch + 1) % self.display_steps == 0:\n",
" c = sess.run(cost, feed_dict={X: x, Y: y})\n",
" print(\"Epoch: {0}, cost = {1}, W = {2}, b = {3}\".format(epoch + 1, c, W, b))\n",
"\n",
" print('Optimization finished ......')\n",
" training_cost = sess.run(cost, feed_dict={X: x, Y: y.reshape(-1, 1)})\n",
" self.W = sess.run(W)\n",
" self.b = sess.run(b)\n",
" print('Training cost = {0}, W = {1}, b = {2}'.format(training_cost, self.W, self.b))\n",
"\n",
" def predict(self, x):\n",
" num_features = x.shape[1]\n",
" X = tf.placeholder(\"float\", shape=[None, num_features])\n",
" with tf.Session() as sess:\n",
" ret = sess.run(tf.add(tf.matmul(X, self.W), self.b), feed_dict={X: x})\n",
" return np.squeeze(ret)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"为了与alpha-mind的框架对接,还需要定义如下一个wrapper。这个wrapper需要实现*load* 和*save* 两种方法。"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"class LinearRegressionTF(create_model_base()):\n",
" def __init__(self, features, fit_target, **kwargs):\n",
" super().__init__(features=features, fit_target=fit_target)\n",
" self.impl = LinearRegressionImpl(**kwargs)\n",
"\n",
" @classmethod\n",
" def load(cls, model_desc: dict):\n",
" return super().load(model_desc)\n",
"\n",
" def save(self):\n",
" model_desc = super().save()\n",
" model_desc['weight'] = self.impl.result()\n",
" return model_desc\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 测试Tensorflow模型\n",
" \n",
"### 数据配置\n",
"------------"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {},
"outputs": [],
"source": [
"freq = '60b'\n",
"universe = Universe('zz800')\n",
"batch = 1\n",
"neutralized_risk = industry_styles\n",
"risk_model = 'short'\n",
"pre_process = [winsorize_normal, standardize]\n",
"post_process = [standardize]\n",
"warm_start = 3\n",
"data_source = os.environ['DB_URI']\n",
"horizon = map_freq(freq)\n",
"\n",
"engine = SqlEngine(data_source)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"我们使用当期的`roe_q`因子,来尝试预测未来大概一个月以后的`roe_q`因子。\n",
"\n",
"* 训练的股票池为`zz800`;;\n",
"* 因子都经过中性化以及标准化等预处理;\n",
"* 预测模型使用线性模型,以20个工作日为一个时间间隔,用过去4期的数据作为训练用特征。"
]
},
{
"cell_type": "code",
"execution_count": 56,
"metadata": {},
"outputs": [],
"source": [
"\n",
"kernal_feature = 'roe_q'\n",
"regress_features = {kernal_feature: LAST(kernal_feature),\n",
" kernal_feature + '_l1': SHIFT(kernal_feature, 1),\n",
" kernal_feature + '_l2': SHIFT(kernal_feature, 2),\n",
" kernal_feature + '_l3': SHIFT(kernal_feature, 3)\n",
" }\n",
"fit_target = [kernal_feature]\n",
"\n",
"data_meta = DataMeta(freq=freq,\n",
" universe=universe,\n",
" batch=batch,\n",
" neutralized_risk=neutralized_risk,\n",
" risk_model=risk_model,\n",
" pre_process=pre_process,\n",
" post_process=post_process,\n",
" warm_start=warm_start,\n",
" data_source=data_source)\n",
"\n",
"regression_model_tf = LinearRegressionTF(features=regress_features, fit_target=fit_target, training_epochs=400, learning_rate=0.01)\n",
"regression_composer_tf = Composer(alpha_model=regression_model_tf, data_meta=data_meta)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 模型对比(sklearn线性回归模型 v.s. tensorflow线性回归模型): IC 系数\n",
"------------------"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### model train and predict\n",
"- train: 给定ref_date, 模型提取ref_date之前的所有训练日期的因子数据,以及ref_date当日的收益率数据进行训练。\n",
"- predict: 给定ref_date, 模型提取ref_date当日的因子数据,预测下一期的收益率数据。\n",
"- ic:给定ref_date, 模型用预测的结果与下一期真实的收益率数据求相关性。"
]
},
{
"cell_type": "code",
"execution_count": 58,
"metadata": {},
"outputs": [],
"source": [
"ref_date = '2017-01-31'\n",
"ref_date = adjustDateByCalendar('china.sse', ref_date).strftime('%Y-%m-%d')"
]
},
{
"cell_type": "code",
"execution_count": 59,
"metadata": {},
"outputs": [],
"source": [
"regression_model_sk = LinearRegression(features=regress_features, fit_target=fit_target)\n",
"regression_composer_sk = Composer(alpha_model=regression_model_sk, data_meta=data_meta)"
]
},
{
"cell_type": "code",
"execution_count": 60,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"E:\\workarea\\software\\conda3\\lib\\site-packages\\alpha_mind-0.2.0-py3.6-win-amd64.egg\\alphamind\\data\\transformer.py:76: FutureWarning: Method .as_matrix will be removed in a future version. Use .values instead.\n",
" dropna=False)\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Optimization finished ......\n",
"Training cost = 0.012139828875660896, W = [[ 0.9230019 ]\n",
" [-0.39638188]\n",
" [ 0.4401099 ]\n",
" [ 0.01593331]], b = -0.03707847744226456\n",
"\n",
"Sklearn Regression Testing IC: 0.5464\n",
"Tensorflow Regression Testing IC: 0.6427\n"
]
}
],
"source": [
"regression_composer_sk.train(ref_date)\n",
"regression_composer_tf.train(ref_date)\n",
"print(\"\\nSklearn Regression Testing IC: {0:.4f}\".format(regression_composer_sk.ic(ref_date=ref_date)))\n",
"print(\"Tensorflow Regression Testing IC: {0:.4f}\".format(regression_composer_tf.ic(ref_date=ref_date)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 回测( simple long short strategy)\n",
"--------------------------"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 策略的初始化\n",
"\n",
"#### 加载数据: \n",
"使用函数 *fetch_data_package* 加载\n",
"- 因子数据\n",
"- 行业数据\n",
"- 风险模型数据\n",
"- 数据的预处理"
]
},
{
"cell_type": "code",
"execution_count": 47,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"2018-08-09 11:13:07,623 - ALPHA_MIND - INFO - Starting data package fetching ...\n",
"E:\\workarea\\software\\conda3\\lib\\site-packages\\alpha_mind-0.2.0-py3.6-win-amd64.egg\\alphamind\\data\\transformer.py:76: FutureWarning: Method .as_matrix will be removed in a future version. Use .values instead.\n",
" dropna=False)\n",
"2018-08-09 11:13:08,138 - ALPHA_MIND - INFO - factor data loading finished\n",
"2018-08-09 11:13:57,280 - ALPHA_MIND - INFO - fit target data loading finished\n",
"2018-08-09 11:13:58,303 - ALPHA_MIND - INFO - industry data loading finished\n",
"2018-08-09 11:13:58,486 - ALPHA_MIND - INFO - benchmark data loading finished\n",
"2018-08-09 11:13:59,791 - ALPHA_MIND - INFO - data merging finished\n",
"2018-08-09 11:13:59,862 - ALPHA_MIND - INFO - Loading data is finished\n",
"2018-08-09 11:13:59,885 - ALPHA_MIND - INFO - Data processing is finished\n"
]
}
],
"source": [
"start_date = '2011-01-01'\n",
"end_date = '2012-01-01'\n",
"\n",
"data_package2 = fetch_data_package(engine,\n",
" alpha_factors=[kernal_feature],\n",
" start_date=start_date,\n",
" end_date=end_date,\n",
" frequency=freq,\n",
" universe=universe,\n",
" benchmark=906,\n",
" warm_start=warm_start,\n",
" batch=1,\n",
" neutralized_risk=neutralized_risk,\n",
" pre_process=pre_process,\n",
" post_process=post_process)\n",
"\n",
"model_dates = [d.strftime('%Y-%m-%d') for d in list(data_package2['predict']['x'].keys())]\n",
"\n",
"\n",
"industry_name = 'sw_adj'\n",
"industry_level = 1\n",
"\n",
"industry_names = industry_list(industry_name, industry_level)\n",
"industry_total = engine.fetch_industry_matrix_range(universe, dates=model_dates, category=industry_name, level=industry_level)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 运行策略:(sklearn线性回归模型 v.s. tensorflow线性回归模型)"
]
},
{
"cell_type": "code",
"execution_count": 61,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"2018-08-09 11:26:33,244 - ALPHA_MIND - INFO - 2011-01-04 full re-balance: 799\n",
"E:\\workarea\\software\\conda3\\lib\\site-packages\\alpha_mind-0.2.0-py3.6-win-amd64.egg\\alphamind\\data\\transformer.py:76: FutureWarning: Method .as_matrix will be removed in a future version. Use .values instead.\n",
" dropna=False)\n",
"2018-08-09 11:26:37,099 - ALPHA_MIND - INFO - 2011-01-04 is finished\n",
"2018-08-09 11:26:37,109 - ALPHA_MIND - INFO - 2011-04-07 full re-balance: 798\n",
"2018-08-09 11:26:41,181 - ALPHA_MIND - INFO - 2011-04-07 is finished\n",
"2018-08-09 11:26:41,191 - ALPHA_MIND - INFO - 2011-07-04 full re-balance: 798\n",
"2018-08-09 11:26:45,093 - ALPHA_MIND - INFO - 2011-07-04 is finished\n",
"2018-08-09 11:26:45,104 - ALPHA_MIND - INFO - 2011-09-27 full re-balance: 797\n",
"2018-08-09 11:26:49,010 - ALPHA_MIND - INFO - 2011-09-27 is finished\n",
"2018-08-09 11:26:49,021 - ALPHA_MIND - INFO - 2011-12-27 full re-balance: 798\n",
"2018-08-09 11:26:52,937 - ALPHA_MIND - INFO - 2011-12-27 is finished\n"
]
}
],
"source": [
"rets1 = []\n",
"rets2 = []\n",
"\n",
"\n",
"\n",
"for i, ref_date in enumerate(model_dates):\n",
" py_ref_date = dt.datetime.strptime(ref_date, '%Y-%m-%d')\n",
" industry_matrix = industry_total[industry_total.trade_date == ref_date]\n",
" dx_returns = pd.DataFrame({'dx': data_package2['predict']['y'][py_ref_date].flatten(),\n",
" 'code': data_package2['predict']['code'][py_ref_date].flatten()})\n",
" \n",
" res = pd.merge(dx_returns, industry_matrix, on=['code']).dropna()\n",
" codes = res.code.values.tolist()\n",
" \n",
" alpha_logger.info('{0} full re-balance: {1}'.format(ref_date, len(codes)))\n",
" \n",
" ## sklearn regression model\n",
" \n",
" raw_predict1 = regression_composer_sk.predict(ref_date).loc[codes]\n",
" er1 = raw_predict1.fillna(raw_predict1.median()).values\n",
" \n",
" target_pos1, _ = er_portfolio_analysis(er1,\n",
" res.industry_name.values,\n",
" None,\n",
" None,\n",
" False,\n",
" None,\n",
" method='ls')\n",
" \n",
" target_pos1['code'] = codes\n",
" result1 = pd.merge(target_pos1, dx_returns, on=['code'])\n",
" ret1 = result1.weight.values @ (np.exp(result1.dx.values) - 1.)\n",
" rets1.append(np.log(1. + ret1))\n",
"\n",
" ## tensorflow regression model\n",
" \n",
" raw_predict2 = regression_composer_tf.predict(ref_date).loc[codes]\n",
" er2 = raw_predict2.fillna(raw_predict2.median()).values\n",
" \n",
" target_pos2, _ = er_portfolio_analysis(er2,\n",
" res.industry_name.values,\n",
" None,\n",
" None,\n",
" False,\n",
" None,\n",
" method='ls')\n",
" \n",
" target_pos2['code'] = codes\n",
" result2 = pd.merge(target_pos2, dx_returns, on=['code'])\n",
" ret2 = result2.weight.values @ (np.exp(result2.dx.values) - 1.)\n",
" rets2.append(np.log(1. + ret2))\n",
" ## perfect forcast\n",
" \n",
" alpha_logger.info('{0} is finished'.format(ref_date))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 收益图对比"
]
},
{
"cell_type": "code",
"execution_count": 62,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.axes._subplots.AxesSubplot at 0x13e1db70>"
]
},
"execution_count": 62,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 864x432 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"ret_df = pd.DataFrame({'sklearn': rets1, 'tensorflow': rets2}, index=model_dates)\n",
"ret_df.loc[advanceDateByCalendar('china.sse', model_dates[-1], freq).strftime('%Y-%m-%d')] = 0.\n",
"ret_df = ret_df.shift(1)\n",
"ret_df.iloc[0] = 0.\n",
"\n",
"ret_df[['sklearn', 'tensorflow']].cumsum().plot(figsize=(12, 6),\n",
" title='Fixed freq rebalanced: {0}'.format(freq))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.5"
},
"varInspector": {
"cols": {
"lenName": 16.0,
"lenType": 16.0,
"lenVar": 40.0
},
"kernels_config": {
"python": {
"delete_cmd_postfix": "",
"delete_cmd_prefix": "del ",
"library": "var_list.py",
"varRefreshCmd": "print(var_dic_list())"
},
"r": {
"delete_cmd_postfix": ") ",
"delete_cmd_prefix": "rm(",
"library": "var_list.r",
"varRefreshCmd": "cat(var_dic_list()) "
}
},
"types_to_exclude": [
"module",
"function",
"builtin_function_or_method",
"instance",
"_Feature"
],
"window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 2
}
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"* 本例展示如何在alpha-mind中使用深度学习模型。 \n",
" - 为方便比较,使用的数据参数与[机器学习模型示例](https://github.com/alpha-miner/alpha-mind/blob/master/notebooks/Example%2012%20-%20Machine%20Learning%20Model%20Prediction.ipynb)一致。\n",
" - 本例以Keras实现深度学习模型,故需要预装Keras。\n",
"\n",
"* 请在环境变量中设置`DB_URI`指向数据库"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {},
"outputs": [],
"source": [
"%matplotlib inline\n",
"\n",
"import os\n",
"import datetime as dt\n",
"import numpy as np\n",
"import pandas as pd\n",
"from alphamind.api import *\n",
"from PyFin.api import *\n",
"from keras.models import Sequential\n",
"from keras.layers import Dense \n",
"from alphamind.model.modelbase import create_model_base"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 使用Keras构建模型(以线性回归为例)\n",
"\n",
"### 构建Keras的接口模型\n",
"\n",
"- alpha-mind中所有的模型算法都是通过底层接口模型实现的。在接口模型中都有统一的训练与预测方法,即*fit* 和 *predict*。\n",
"- 下面的代码就是创建一个接口类,使用Keras实现线性回归的算法。*fit* 和 *predict* 分别对应拟合与预测功能。"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {},
"outputs": [],
"source": [
"class LinearRegressionImpl(object):\n",
" def __init__(self, **kwargs):\n",
" self.learning_rate = kwargs.get('learning_rate', 0.01)\n",
" self.training_epochs = kwargs.get('training_epochs', 10)\n",
" self.display_steps = kwargs.get('display_steps', None)\n",
" self.W = None\n",
" self.b = None\n",
"\n",
" def result(self):\n",
" with tf.Session() as sess:\n",
" ret = [sess.run(self.W), sess.run(self.b)]\n",
" return ret\n",
"\n",
" def fit(self, x, y):\n",
" num_samples, num_features = x.shape\n",
"\n",
" output_dim = 1\n",
" input_dim = num_features\n",
" model = Sequential()\n",
" model.add(Dense(output_dim, input_dim=input_dim, kernel_initializer='normal', activation='linear'))\n",
" model.compile(loss='mean_squared_error', optimizer='adam')\n",
" model.fit(x, y, epochs=self.training_epochs, verbose=)\n",
"\n",
" print('Optimization finished ......')\n",
" self.model = model\n",
"\n",
" def predict(self, x):\n",
" ret = self.model.predict(x)\n",
" return np.squeeze(ret)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"为了与alpha-mind的框架对接,还需要定义如下一个wrapper。这个wrapper需要实现*load* 和*save* 两种方法。"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {},
"outputs": [],
"source": [
"class LinearRegressionKS(create_model_base()):\n",
" def __init__(self, features, fit_target, **kwargs):\n",
" super().__init__(features=features, fit_target=fit_target)\n",
" self.impl = LinearRegressionImpl(**kwargs)\n",
"\n",
" @classmethod\n",
" def load(cls, model_desc: dict):\n",
" return super().load(model_desc)\n",
"\n",
" def save(self):\n",
" model_desc = super().save()\n",
" model_desc['weight'] = self.impl.result()\n",
" return model_desc\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 测试Keras模型\n",
" \n",
"### 数据配置\n",
"------------"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [],
"source": [
"freq = '60b'\n",
"universe = Universe('zz800')\n",
"batch = 1\n",
"neutralized_risk = industry_styles\n",
"risk_model = 'short'\n",
"pre_process = [winsorize_normal, standardize]\n",
"post_process = [standardize]\n",
"warm_start = 3\n",
"data_source = os.environ['DB_URI']\n",
"horizon = map_freq(freq)\n",
"\n",
"engine = SqlEngine(data_source)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"我们使用当期的`roe_q`因子,来尝试预测未来大概一个月以后的`roe_q`因子。\n",
"\n",
"* 训练的股票池为`zz800`;;\n",
"* 因子都经过中性化以及标准化等预处理;\n",
"* 预测模型使用线性模型,以20个工作日为一个时间间隔,用过去4期的数据作为训练用特征。"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [],
"source": [
"\n",
"kernal_feature = 'roe_q'\n",
"regress_features = {kernal_feature: LAST(kernal_feature),\n",
" kernal_feature + '_l1': SHIFT(kernal_feature, 1),\n",
" kernal_feature + '_l2': SHIFT(kernal_feature, 2),\n",
" kernal_feature + '_l3': SHIFT(kernal_feature, 3)\n",
" }\n",
"fit_target = [kernal_feature]\n",
"\n",
"data_meta = DataMeta(freq=freq,\n",
" universe=universe,\n",
" batch=batch,\n",
" neutralized_risk=neutralized_risk,\n",
" risk_model=risk_model,\n",
" pre_process=pre_process,\n",
" post_process=post_process,\n",
" warm_start=warm_start,\n",
" data_source=data_source)\n",
"\n",
"regression_model_ks = LinearRegressionKS(features=regress_features, fit_target=fit_target, training_epochs=400)\n",
"regression_composer_ks = Composer(alpha_model=regression_model_ks, data_meta=data_meta)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 模型对比(sklearn线性回归模型 v.s. keras线性回归模型): IC 系数\n",
"------------------"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### model train and predict\n",
"- train: 给定ref_date, 模型提取ref_date之前的所有训练日期的因子数据,以及ref_date当日的收益率数据进行训练。\n",
"- predict: 给定ref_date, 模型提取ref_date当日的因子数据,预测下一期的收益率数据。\n",
"- ic:给定ref_date, 模型用预测的结果与下一期真实的收益率数据求相关性。"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [],
"source": [
"ref_date = '2017-01-31'\n",
"ref_date = adjustDateByCalendar('china.sse', ref_date).strftime('%Y-%m-%d')"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {},
"outputs": [],
"source": [
"regression_model_sk = LinearRegression(features=regress_features, fit_target=fit_target)\n",
"regression_composer_sk = Composer(alpha_model=regression_model_sk, data_meta=data_meta)"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"E:\\workarea\\software\\conda3\\lib\\site-packages\\alpha_mind-0.2.0-py3.6-win-amd64.egg\\alphamind\\data\\transformer.py:76: FutureWarning: Method .as_matrix will be removed in a future version. Use .values instead.\n",
" dropna=False)\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Optimization finished ......\n",
"\n",
"Sklearn Regression Testing IC: 0.5464\n",
"Keras Regression Testing IC: 0.5462\n"
]
}
],
"source": [
"regression_composer_sk.train(ref_date)\n",
"regression_composer_ks.train(ref_date)\n",
"print(\"\\nSklearn Regression Testing IC: {0:.4f}\".format(regression_composer_sk.ic(ref_date=ref_date)))\n",
"print(\"Keras Regression Testing IC: {0:.4f}\".format(regression_composer_ks.ic(ref_date=ref_date)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 回测( simple long short strategy)\n",
"--------------------------"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 策略的初始化\n",
"\n",
"#### 加载数据: fetch_data_package\n",
"- 因子数据\n",
"- 行业数据\n",
"- 风险模型数据\n",
"- 数据的预处理"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"2018-08-09 13:35:24,689 - ALPHA_MIND - INFO - Starting data package fetching ...\n",
"E:\\workarea\\software\\conda3\\lib\\site-packages\\alpha_mind-0.2.0-py3.6-win-amd64.egg\\alphamind\\data\\transformer.py:76: FutureWarning: Method .as_matrix will be removed in a future version. Use .values instead.\n",
" dropna=False)\n",
"2018-08-09 13:35:25,457 - ALPHA_MIND - INFO - factor data loading finished\n",
"2018-08-09 13:36:15,526 - ALPHA_MIND - INFO - fit target data loading finished\n",
"2018-08-09 13:36:15,774 - ALPHA_MIND - INFO - industry data loading finished\n",
"2018-08-09 13:36:15,918 - ALPHA_MIND - INFO - benchmark data loading finished\n",
"2018-08-09 13:36:16,656 - ALPHA_MIND - INFO - data merging finished\n",
"2018-08-09 13:36:16,714 - ALPHA_MIND - INFO - Loading data is finished\n",
"2018-08-09 13:36:16,748 - ALPHA_MIND - INFO - Data processing is finished\n"
]
}
],
"source": [
"start_date = '2011-01-01'\n",
"end_date = '2012-01-01'\n",
"\n",
"data_package2 = fetch_data_package(engine,\n",
" alpha_factors=[kernal_feature],\n",
" start_date=start_date,\n",
" end_date=end_date,\n",
" frequency=freq,\n",
" universe=universe,\n",
" benchmark=906,\n",
" warm_start=warm_start,\n",
" batch=1,\n",
" neutralized_risk=neutralized_risk,\n",
" pre_process=pre_process,\n",
" post_process=post_process)\n",
"\n",
"model_dates = [d.strftime('%Y-%m-%d') for d in list(data_package2['predict']['x'].keys())]\n",
"\n",
"\n",
"industry_name = 'sw_adj'\n",
"industry_level = 1\n",
"\n",
"industry_names = industry_list(industry_name, industry_level)\n",
"industry_total = engine.fetch_industry_matrix_range(universe, dates=model_dates, category=industry_name, level=industry_level)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 运行策略:(sklearn线性回归模型 v.s.keras线性回归模型)"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"2018-08-09 13:36:59,018 - ALPHA_MIND - INFO - 2011-01-04 full re-balance: 799\n",
"E:\\workarea\\software\\conda3\\lib\\site-packages\\alpha_mind-0.2.0-py3.6-win-amd64.egg\\alphamind\\data\\transformer.py:76: FutureWarning: Method .as_matrix will be removed in a future version. Use .values instead.\n",
" dropna=False)\n",
"2018-08-09 13:37:03,020 - ALPHA_MIND - INFO - 2011-01-04 is finished\n",
"2018-08-09 13:37:03,028 - ALPHA_MIND - INFO - 2011-04-07 full re-balance: 798\n",
"2018-08-09 13:37:06,784 - ALPHA_MIND - INFO - 2011-04-07 is finished\n",
"2018-08-09 13:37:06,794 - ALPHA_MIND - INFO - 2011-07-04 full re-balance: 798\n",
"2018-08-09 13:37:10,646 - ALPHA_MIND - INFO - 2011-07-04 is finished\n",
"2018-08-09 13:37:10,655 - ALPHA_MIND - INFO - 2011-09-27 full re-balance: 797\n",
"2018-08-09 13:37:14,539 - ALPHA_MIND - INFO - 2011-09-27 is finished\n",
"2018-08-09 13:37:14,548 - ALPHA_MIND - INFO - 2011-12-27 full re-balance: 798\n",
"2018-08-09 13:37:18,448 - ALPHA_MIND - INFO - 2011-12-27 is finished\n"
]
}
],
"source": [
"rets1 = []\n",
"rets2 = []\n",
"\n",
"\n",
"\n",
"for i, ref_date in enumerate(model_dates):\n",
" py_ref_date = dt.datetime.strptime(ref_date, '%Y-%m-%d')\n",
" industry_matrix = industry_total[industry_total.trade_date == ref_date]\n",
" dx_returns = pd.DataFrame({'dx': data_package2['predict']['y'][py_ref_date].flatten(),\n",
" 'code': data_package2['predict']['code'][py_ref_date].flatten()})\n",
" \n",
" res = pd.merge(dx_returns, industry_matrix, on=['code']).dropna()\n",
" codes = res.code.values.tolist()\n",
" \n",
" alpha_logger.info('{0} full re-balance: {1}'.format(ref_date, len(codes)))\n",
" \n",
" ## sklearn regression model\n",
" \n",
" raw_predict1 = regression_composer_sk.predict(ref_date).loc[codes]\n",
" er1 = raw_predict1.fillna(raw_predict1.median()).values\n",
" \n",
" target_pos1, _ = er_portfolio_analysis(er1,\n",
" res.industry_name.values,\n",
" None,\n",
" None,\n",
" False,\n",
" None,\n",
" method='ls')\n",
" \n",
" target_pos1['code'] = codes\n",
" result1 = pd.merge(target_pos1, dx_returns, on=['code'])\n",
" ret1 = result1.weight.values @ (np.exp(result1.dx.values) - 1.)\n",
" rets1.append(np.log(1. + ret1))\n",
"\n",
" ## keras regression model\n",
" \n",
" raw_predict2 = regression_composer_ks.predict(ref_date).loc[codes]\n",
" er2 = raw_predict2.fillna(raw_predict2.median()).values\n",
" \n",
" target_pos2, _ = er_portfolio_analysis(er2,\n",
" res.industry_name.values,\n",
" None,\n",
" None,\n",
" False,\n",
" None,\n",
" method='ls')\n",
" \n",
" target_pos2['code'] = codes\n",
" result2 = pd.merge(target_pos2, dx_returns, on=['code'])\n",
" ret2 = result2.weight.values @ (np.exp(result2.dx.values) - 1.)\n",
" rets2.append(np.log(1. + ret2))\n",
" ## perfect forcast\n",
" \n",
" alpha_logger.info('{0} is finished'.format(ref_date))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"#### 收益图对比"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"<matplotlib.axes._subplots.AxesSubplot at 0x12194748>"
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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2vD0009z1113/eU1U6dOZerUqTRo0ADwFdlr167lqquuolevXowZMwaAzZs3s3btWkqVKkVoaCjt2rX7035uvfVWABo2bMjXX3+d6+MVERERyS8ysxyhIfn7QgeBGHFOASpnW64EbM22XAyoA8w0s41AY2B8TicIOuf6OefinXPxZcqUCUC0wLvwwgtJSkqibt26PPfcc7z22msANGnShEmTJuGc+8trnHM899xzLF68mMWLF7Nu3Truu+8+Zs6cybRp05g7dy5LliyhQYMGf1xOLioqitDQ0D/tJzIyEoDQ0FAyMjLO8pGKiIiI5I1tqYe4/oNZ/LTurxdbyE8CMeK8AKhuZtWALUB7oMPRjc65VKD00WUzmwl0c84l5qbTk40Mny1bt24lLi6Ojh07EhMTw6BBgwB47bXXeP3113n44Yf55JNP/vSali1b8tJLL3HXXXcRExPDli1bCA8PJzU1lZIlSxIdHc2qVauYN2+eB0ckIiIi4p3fDxyh84AE9qfuoniR/H3341yPODvnMoBHgClAMjDSObfCzF4zs5tzu//8ZtmyZTRq1IiLL76YN998kxdffPGPbe+//z5paWk8/fTTf3pNixYt6NChA5dffjl169bltttuY9++fbRq1YqMjAzq1avHSy+9ROPGjfP6cEREREQ8s/9wBl0GLSB690pmRz5Bnd+neR3phCynqQX5QXx8vEtM/POgdHJyMjVr1vQoUXDQeyQiIiLB4HBGJvcOWsCvG1YwsdibREYWgXsnQ4nKJ39xgJlZknPupPcZCcRUDRERERGRU5aZ5Xhi+GLWr1vD9JI9iDSg81hPiubTocJZRERERPKMc47nv17GvOVr+L5UT4qm74Mu30Dp6l5HOykVziIiIiKSZ96avIpvE9cwrXQvSh7aAp2+hgoNvI51SlQ4i4iIiEie6PPDegb9sIqJpT+m/IHVcMdQqNrU61inTIWziIiIiJx1wxN+ofukFXxdegDn70+CW/rCRTd4Heu0qHAWERERkbNq0rJtPD9mKYNKDaX+/tnQ6i2o397rWKctEHcOLFQ2btxInTp1vI4hIiIiEhTmrN3J48MX0bPkaK46MAWufgYaP+R1rDOiwjmPZGZmeh1BREREJE8t+uV3un6eyHPFJtHm4NfQqCtc85zXsc6YCudc2LBhAw0aNGD+/Pn861//4tJLL6Ve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\n",
"text/plain": [
"<Figure size 864x432 with 1 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"ret_df = pd.DataFrame({'sklearn': rets1, 'keras': rets2}, index=model_dates)\n",
"ret_df.loc[advanceDateByCalendar('china.sse', model_dates[-1], freq).strftime('%Y-%m-%d')] = 0.\n",
"ret_df = ret_df.shift(1)\n",
"ret_df.iloc[0] = 0.\n",
"\n",
"ret_df[['sklearn', 'keras']].cumsum().plot(figsize=(12, 6),\n",
" title='Fixed freq rebalanced: {0}'.format(freq))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.5"
},
"varInspector": {
"cols": {
"lenName": 16.0,
"lenType": 16.0,
"lenVar": 40.0
},
"kernels_config": {
"python": {
"delete_cmd_postfix": "",
"delete_cmd_prefix": "del ",
"library": "var_list.py",
"varRefreshCmd": "print(var_dic_list())"
},
"r": {
"delete_cmd_postfix": ") ",
"delete_cmd_prefix": "rm(",
"library": "var_list.r",
"varRefreshCmd": "cat(var_dic_list()) "
}
},
"types_to_exclude": [
"module",
"function",
"builtin_function_or_method",
"instance",
"_Feature"
],
"window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment