Commit 7f7d2df6 authored by Dr.李's avatar Dr.李

FIX: wrong calculation of returns

parent c14a3881
...@@ -90,7 +90,8 @@ macro_styles = ['COUNTRY'] ...@@ -90,7 +90,8 @@ macro_styles = ['COUNTRY']
total_risk_factors = risk_styles + industry_styles + macro_styles total_risk_factors = risk_styles + industry_styles + macro_styles
_map_index_codes = { _map_index_codes = {
300: "2070000060" 300: "2070000060",
905: "2070000187",
} }
...@@ -128,8 +129,8 @@ class SqlEngine: ...@@ -128,8 +129,8 @@ class SqlEngine:
def _create_stats(self, df, horizon, offset): def _create_stats(self, df, horizon, offset):
df.set_index("trade_date", inplace=True) df.set_index("trade_date", inplace=True)
df["dx"] = np.log(1. + df["chgPct"]) df["dx"] = np.log(1. + df["chgPct"] / 100.)
df = df.groupby("code").rolling(window=horizon + 1)['dx'].sum().shift(-(offset + 1)).dropna().reset_index() df = df.groupby("code").rolling(window=horizon + 1)['dx'].sum().groupby(level=0).shift(-(horizon + offset + 1)).dropna().reset_index()
return df return df
def fetch_dx_return(self, def fetch_dx_return(self,
...@@ -271,6 +272,7 @@ class SqlEngine: ...@@ -271,6 +272,7 @@ class SqlEngine:
df = pd.read_sql(query, self.session.bind).dropna() df = pd.read_sql(query, self.session.bind).dropna()
df = self._create_stats(df, horizon, offset) df = self._create_stats(df, horizon, offset)
df["trade_date"] = pd.to_datetime(df["trade_date"])
if dates: if dates:
df = df[df.trade_date.isin(dates)] df = df[df.trade_date.isin(dates)]
...@@ -412,6 +414,7 @@ class SqlEngine: ...@@ -412,6 +414,7 @@ class SqlEngine:
res['chgPct'] = df.chgPct res['chgPct'] = df.chgPct
res['secShortName'] = df['secShortName'] res['secShortName'] = df['secShortName']
res = res.reset_index() res = res.reset_index()
res["trade_date"] = pd.to_datetime(res["trade_date"])
return pd.merge(res, universe_df[['trade_date', 'code']], how='inner').drop_duplicates( return pd.merge(res, universe_df[['trade_date', 'code']], how='inner').drop_duplicates(
['trade_date', 'code']) ['trade_date', 'code'])
...@@ -487,7 +490,9 @@ class SqlEngine: ...@@ -487,7 +490,9 @@ class SqlEngine:
) )
).distinct() ).distinct()
return pd.read_sql(query, self.session.bind) df = pd.read_sql(query, self.session.bind)
df["trade_date"] = pd.to_datetime(df["trade_date"])
return df
def fetch_risk_model(self, def fetch_risk_model(self,
ref_date: str, ref_date: str,
...@@ -561,6 +566,7 @@ class SqlEngine: ...@@ -561,6 +566,7 @@ class SqlEngine:
cond cond
) )
risk_cov = pd.read_sql(query, self.engine).sort_values(['trade_date', 'FactorID']) risk_cov = pd.read_sql(query, self.engine).sort_values(['trade_date', 'FactorID'])
risk_cov["trade_date"] = pd.to_datetime(risk_cov["trade_date"])
if not excluded: if not excluded:
excluded = [] excluded = []
...@@ -591,6 +597,7 @@ class SqlEngine: ...@@ -591,6 +597,7 @@ class SqlEngine:
.distinct() .distinct()
risk_exp = pd.read_sql(query, self.engine).sort_values(['trade_date', 'code']).dropna() risk_exp = pd.read_sql(query, self.engine).sort_values(['trade_date', 'code']).dropna()
risk_exp["trade_date"] = pd.to_datetime(risk_exp["trade_date"])
if not model_type: if not model_type:
return risk_cov, risk_exp return risk_cov, risk_exp
...@@ -711,7 +718,9 @@ class SqlEngine: ...@@ -711,7 +718,9 @@ class SqlEngine:
IndexComponent.indexCode == benchmark, IndexComponent.indexCode == benchmark,
) )
).distinct() ).distinct()
return pd.read_sql(query, self.engine) df = pd.read_sql(query, self.engine)
df["trade_date"] = pd.to_datetime(df["trade_date"])
return df
def fetch_data(self, def fetch_data(self,
ref_date: str, ref_date: str,
...@@ -803,7 +812,7 @@ if __name__ == "__main__": ...@@ -803,7 +812,7 @@ if __name__ == "__main__":
sql_engine = SqlEngine(db_url=db_url) sql_engine = SqlEngine(db_url=db_url)
universe = Universe("hs300") universe = Universe("hs300")
start_date = '2020-01-01' start_date = '2020-01-01'
end_date = '2020-04-21' end_date = '2020-02-21'
benchmark = 300 benchmark = 300
factors = ["EMA5D", "EMV6D"] factors = ["EMA5D", "EMV6D"]
ref_dates = makeSchedule(start_date, end_date, "10b", 'china.sse') ref_dates = makeSchedule(start_date, end_date, "10b", 'china.sse')
...@@ -815,45 +824,45 @@ if __name__ == "__main__": ...@@ -815,45 +824,45 @@ if __name__ == "__main__":
# print(df) # print(df)
# df = sql_engine.fetch_dx_return("2020-10-09", codes=["2010031963"]) # df = sql_engine.fetch_dx_return("2020-10-09", codes=["2010031963"])
# print(df) # print(df)
df = sql_engine.fetch_dx_return_range(universe, dates=ref_dates, horizon=9) df = sql_engine.fetch_dx_return_range(universe, dates=ref_dates, horizon=9, offset=1)
print(df)
df = sql_engine.fetch_dx_return_index("2020-10-09", index_code=benchmark)
print(df)
df = sql_engine.fetch_dx_return_index_range(start_date=start_date, end_date=end_date, index_code=benchmark)
print(df)
df = sql_engine.fetch_benchmark("2020-10-09", benchmark=benchmark)
print(df)
df = sql_engine.fetch_benchmark_range(start_date=start_date, end_date=end_date, benchmark=benchmark)
print(df)
df = sql_engine.fetch_industry(ref_date="2020-10-09", codes=["2010031963"])
print(df)
df = sql_engine.fetch_industry_matrix(ref_date="2020-10-09", codes=["2010031963"])
print(df)
df = sql_engine.fetch_industry_matrix_range(universe=universe,
start_date=start_date,
end_date=end_date)
print(df)
df = sql_engine.fetch_industry_range(start_date=start_date, end_date=end_date, universe=Universe("hs300"))
print(df)
df = sql_engine.fetch_risk_model("2020-02-21", codes=["2010031963"])
print(df)
df = sql_engine.fetch_risk_model("2020-02-21", codes=["2010031963"], model_type="factor")
print(df)
df = sql_engine.fetch_risk_model_range(universe=universe,
start_date=start_date,
end_date=end_date)
print(df)
df = sql_engine.fetch_risk_model_range(universe=universe,
start_date=start_date,
end_date=end_date,
model_type="factor")
print(df) print(df)
df = sql_engine.fetch_data("2020-02-11", factors=factors, codes=["2010031963"], benchmark=300) # df = sql_engine.fetch_dx_return_index("2020-10-09", index_code=benchmark)
print(df) # print(df)
df = sql_engine.fetch_data_range(universe, df = sql_engine.fetch_dx_return_index_range(start_date=start_date, end_date=end_date, index_code=benchmark, horizon=9, offset=1)
factors=factors,
start_date=start_date,
end_date=end_date,
benchmark=300)
print(df) print(df)
# df = sql_engine.fetch_benchmark("2020-10-09", benchmark=benchmark)
# print(df)
# df = sql_engine.fetch_benchmark_range(start_date=start_date, end_date=end_date, benchmark=benchmark)
# print(df)
# df = sql_engine.fetch_industry(ref_date="2020-10-09", codes=["2010031963"])
# print(df)
# df = sql_engine.fetch_industry_matrix(ref_date="2020-10-09", codes=["2010031963"])
# print(df)
# df = sql_engine.fetch_industry_matrix_range(universe=universe,
# start_date=start_date,
# end_date=end_date)
# print(df)
# df = sql_engine.fetch_industry_range(start_date=start_date, end_date=end_date, universe=Universe("hs300"))
# print(df)
# df = sql_engine.fetch_risk_model("2020-02-21", codes=["2010031963"])
# print(df)
# df = sql_engine.fetch_risk_model("2020-02-21", codes=["2010031963"], model_type="factor")
# print(df)
# df = sql_engine.fetch_risk_model_range(universe=universe,
# start_date=start_date,
# end_date=end_date)
# print(df)
# df = sql_engine.fetch_risk_model_range(universe=universe,
# start_date=start_date,
# end_date=end_date,
# model_type="factor")
# print(df)
# df = sql_engine.fetch_data("2020-02-11", factors=factors, codes=["2010031963"], benchmark=300)
# print(df)
# df = sql_engine.fetch_data_range(universe,
# factors=factors,
# start_date=start_date,
# end_date=end_date,
# benchmark=benchmark)
# print(df)
...@@ -57,7 +57,9 @@ class BaseUniverse(metaclass=abc.ABCMeta): ...@@ -57,7 +57,9 @@ class BaseUniverse(metaclass=abc.ABCMeta):
*more_conditions *more_conditions
) )
).order_by(UniverseTable.trade_date, UniverseTable.code) ).order_by(UniverseTable.trade_date, UniverseTable.code)
return pd.read_sql(query, engine.engine) df = pd.read_sql(query, engine.engine)
df["trade_date"] = pd.to_datetime(df["trade_date"])
return df
def _query_statements(self, start_date: str = None, end_date: str = None, dates=None): def _query_statements(self, start_date: str = None, end_date: str = None, dates=None):
return and_( return and_(
......
...@@ -35,8 +35,8 @@ ...@@ -35,8 +35,8 @@
"Back test parameter settings\n", "Back test parameter settings\n",
"\"\"\"\n", "\"\"\"\n",
"\n", "\n",
"start_date = '2017-01-01'\n", "start_date = '2020-01-01'\n",
"end_date = '2018-02-24'\n", "end_date = '2020-02-21'\n",
"\n", "\n",
"frequency = '10b'\n", "frequency = '10b'\n",
"industry_lower = 1.0\n", "industry_lower = 1.0\n",
...@@ -49,8 +49,8 @@ ...@@ -49,8 +49,8 @@
"benchmark_total_upper = 1.0\n", "benchmark_total_upper = 1.0\n",
"horizon = map_freq(frequency)\n", "horizon = map_freq(frequency)\n",
"weight_gap = 0.01\n", "weight_gap = 0.01\n",
"benchmark_code = 905\n", "benchmark_code = 300\n",
"universe_name = 'zz800'\n", "universe_name = 'hs300'\n",
"universe = Universe(universe_name)\n", "universe = Universe(universe_name)\n",
"ref_dates = makeSchedule(start_date, end_date, frequency, 'china.sse')\n", "ref_dates = makeSchedule(start_date, end_date, frequency, 'china.sse')\n",
"\n", "\n",
...@@ -70,7 +70,7 @@ ...@@ -70,7 +70,7 @@
"\"\"\"\n", "\"\"\"\n",
"\n", "\n",
"industry_names = industry_list(industry_name, industry_level)\n", "industry_names = industry_list(industry_name, industry_level)\n",
"constraint_risk = ['SIZE', 'SIZENL', 'BETA'] + industry_names\n", "constraint_risk = ['SIZE', 'SIZENL', 'BETA'] + industry_names[:-1]\n",
"total_risk_names = constraint_risk + ['benchmark', 'total']\n", "total_risk_names = constraint_risk + ['benchmark', 'total']\n",
"\n", "\n",
"b_type = []\n", "b_type = []\n",
...@@ -112,9 +112,7 @@ ...@@ -112,9 +112,7 @@
" dates=ref_dates,\n", " dates=ref_dates,\n",
" horizon=horizon,\n", " horizon=horizon,\n",
" offset=1)\n", " offset=1)\n",
"\n",
" return_groups = codes_return.groupby('trade_date')\n", " return_groups = codes_return.groupby('trade_date')\n",
" \n",
" \"\"\"\n", " \"\"\"\n",
" Model phase: we need 1 constant linear model and one linear regression model\n", " Model phase: we need 1 constant linear model and one linear regression model\n",
" \"\"\"\n", " \"\"\"\n",
...@@ -122,7 +120,7 @@ ...@@ -122,7 +120,7 @@
" industry_groups = industry_total.groupby('trade_date')\n", " industry_groups = industry_total.groupby('trade_date')\n",
" \n", " \n",
" alpha_name = [str(factor_name) + '_' + ('pos' if positive else 'neg')]\n", " alpha_name = [str(factor_name) + '_' + ('pos' if positive else 'neg')]\n",
" simple_expression = CSRes(LAST(factor_name), 'ETOP') if positive else -CSRes(LAST(factor_name), 'ETOP')\n", " simple_expression = CSRes(LAST(factor_name), 'EARNYILD') if positive else -CSRes(LAST(factor_name), 'EARNYILD')\n",
"\n", "\n",
" const_features = {alpha_name[0]: simple_expression}\n", " const_features = {alpha_name[0]: simple_expression}\n",
" const_weights = {alpha_name[0]: 1.}\n", " const_weights = {alpha_name[0]: 1.}\n",
...@@ -234,7 +232,7 @@ ...@@ -234,7 +232,7 @@
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"factors = ['EPS', 'ROE']" "factors = [\"EMA5D\", \"EMV6D\"]"
] ]
}, },
{ {
...@@ -243,17 +241,73 @@ ...@@ -243,17 +241,73 @@
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"ename": "AttributeError", "name": "stderr",
"evalue": "'SqlEngine' object has no attribute 'fetch_dx_return_index_range'", "output_type": "stream",
"output_type": "error", "text": [
"traceback": [ "2020-11-15 02:48:08,589 - ALPHA_MIND - INFO - 2020-01-02 00:00:00: 299\n",
"\u001B[1;31m---------------------------------------------------------------------------\u001B[0m", "2020-11-15 02:48:11,898 - ALPHA_MIND - WARNING - winsorize_normal normally should not be done after neutralize\n",
"\u001B[1;31mAttributeError\u001B[0m Traceback (most recent call last)", "2020-11-15 02:48:11,900 - ALPHA_MIND - INFO - 2020-01-02 00:00:00 full re-balance\n",
"\u001B[1;32m<ipython-input-6-994dd70dbf6c>\u001B[0m in \u001B[0;36m<module>\u001B[1;34m\u001B[0m\n\u001B[0;32m 1\u001B[0m \u001B[1;31m# %%time\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m 2\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n\u001B[1;32m----> 3\u001B[1;33m \u001B[0mres1\u001B[0m \u001B[1;33m=\u001B[0m \u001B[1;33m[\u001B[0m\u001B[0mworker_func_positive\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mfactor\u001B[0m\u001B[1;33m)\u001B[0m \u001B[1;32mfor\u001B[0m \u001B[0mfactor\u001B[0m \u001B[1;32min\u001B[0m \u001B[0mfactors\u001B[0m\u001B[1;33m]\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0m\u001B[0;32m 4\u001B[0m \u001B[0mres2\u001B[0m \u001B[1;33m=\u001B[0m \u001B[1;33m[\u001B[0m\u001B[0mworker_func_negative\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mfactor\u001B[0m\u001B[1;33m)\u001B[0m \u001B[1;32mfor\u001B[0m \u001B[0mfactor\u001B[0m \u001B[1;32min\u001B[0m \u001B[0mfactors\u001B[0m\u001B[1;33m]\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m 5\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n", "2020-11-15 02:48:11,921 - ALPHA_MIND - INFO - 2020-01-02 00:00:00 is finished\n",
"\u001B[1;32m<ipython-input-6-994dd70dbf6c>\u001B[0m in \u001B[0;36m<listcomp>\u001B[1;34m(.0)\u001B[0m\n\u001B[0;32m 1\u001B[0m \u001B[1;31m# %%time\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m 2\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n\u001B[1;32m----> 3\u001B[1;33m \u001B[0mres1\u001B[0m \u001B[1;33m=\u001B[0m \u001B[1;33m[\u001B[0m\u001B[0mworker_func_positive\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mfactor\u001B[0m\u001B[1;33m)\u001B[0m \u001B[1;32mfor\u001B[0m \u001B[0mfactor\u001B[0m \u001B[1;32min\u001B[0m \u001B[0mfactors\u001B[0m\u001B[1;33m]\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0m\u001B[0;32m 4\u001B[0m \u001B[0mres2\u001B[0m \u001B[1;33m=\u001B[0m \u001B[1;33m[\u001B[0m\u001B[0mworker_func_negative\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mfactor\u001B[0m\u001B[1;33m)\u001B[0m \u001B[1;32mfor\u001B[0m \u001B[0mfactor\u001B[0m \u001B[1;32min\u001B[0m \u001B[0mfactors\u001B[0m\u001B[1;33m]\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m 5\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n", "2020-11-15 02:48:11,929 - ALPHA_MIND - INFO - 2020-01-16 00:00:00: 300\n",
"\u001B[1;32m<ipython-input-4-e6c1eb1a5c2b>\u001B[0m in \u001B[0;36mworker_func_positive\u001B[1;34m(factor_name)\u001B[0m\n\u001B[0;32m 118\u001B[0m \u001B[1;32mfrom\u001B[0m \u001B[0malphamind\u001B[0m\u001B[1;33m.\u001B[0m\u001B[0mapi\u001B[0m \u001B[1;32mimport\u001B[0m \u001B[0mSqlEngine\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m 119\u001B[0m \u001B[0mengine\u001B[0m \u001B[1;33m=\u001B[0m \u001B[0mSqlEngine\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mdata_source\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[1;32m--> 120\u001B[1;33m \u001B[1;32mreturn\u001B[0m \u001B[0mfactor_analysis\u001B[0m\u001B[1;33m(\u001B[0m\u001B[0mengine\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mfactor_name\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0muniverse\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mbenchmark_code\u001B[0m\u001B[1;33m,\u001B[0m \u001B[0mpositive\u001B[0m\u001B[1;33m=\u001B[0m\u001B[1;32mTrue\u001B[0m\u001B[1;33m)\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0m\u001B[0;32m 121\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m 122\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n", "2020-11-15 02:48:11,933 - ALPHA_MIND - WARNING - winsorize_normal normally should not be done after neutralize\n",
"\u001B[1;32m<ipython-input-4-e6c1eb1a5c2b>\u001B[0m in \u001B[0;36mfactor_analysis\u001B[1;34m(engine, factor_name, universe, benchmark_code, positive)\u001B[0m\n\u001B[0;32m 4\u001B[0m \u001B[0mData\u001B[0m \u001B[0mphase\u001B[0m\u001B[1;33m\u001B[0m\u001B[1;33m\u001B[0m\u001B[0m\n\u001B[0;32m 5\u001B[0m \"\"\"\n\u001B[1;32m----> 6\u001B[1;33m index_return = engine.fetch_dx_return_index_range(benchmark_code, start_date, end_date, horizon=horizon,\n\u001B[0m\u001B[0;32m 7\u001B[0m offset=1).set_index('trade_date')\n\u001B[0;32m 8\u001B[0m \u001B[1;33m\u001B[0m\u001B[0m\n", "2020-11-15 02:48:11,936 - ALPHA_MIND - INFO - 2020-01-16 00:00:00 full re-balance\n",
"\u001B[1;31mAttributeError\u001B[0m: 'SqlEngine' object has no attribute 'fetch_dx_return_index_range'" "2020-11-15 02:48:11,960 - ALPHA_MIND - INFO - 2020-01-16 00:00:00 is finished\n",
"2020-11-15 02:48:11,969 - ALPHA_MIND - INFO - 2020-02-07 00:00:00: 300\n",
"2020-11-15 02:48:11,975 - ALPHA_MIND - WARNING - winsorize_normal normally should not be done after neutralize\n",
"2020-11-15 02:48:11,978 - ALPHA_MIND - INFO - 2020-02-07 00:00:00 full re-balance\n",
"2020-11-15 02:48:12,002 - ALPHA_MIND - INFO - 2020-02-07 00:00:00 is finished\n",
"2020-11-15 02:48:12,012 - ALPHA_MIND - INFO - 2020-02-21 00:00:00: 300\n",
"2020-11-15 02:48:12,018 - ALPHA_MIND - WARNING - winsorize_normal normally should not be done after neutralize\n",
"2020-11-15 02:48:12,020 - ALPHA_MIND - INFO - 2020-02-21 00:00:00 full re-balance\n",
"2020-11-15 02:48:12,044 - ALPHA_MIND - INFO - 2020-02-21 00:00:00 is finished\n",
"2020-11-15 02:48:13,897 - ALPHA_MIND - INFO - 2020-01-02 00:00:00: 300\n",
"2020-11-15 02:48:13,901 - ALPHA_MIND - WARNING - winsorize_normal normally should not be done after neutralize\n",
"2020-11-15 02:48:13,903 - ALPHA_MIND - INFO - 2020-01-02 00:00:00 full re-balance\n",
"2020-11-15 02:48:13,932 - ALPHA_MIND - INFO - 2020-01-02 00:00:00 is finished\n",
"2020-11-15 02:48:13,940 - ALPHA_MIND - INFO - 2020-01-16 00:00:00: 300\n",
"2020-11-15 02:48:13,946 - ALPHA_MIND - WARNING - winsorize_normal normally should not be done after neutralize\n",
"2020-11-15 02:48:13,949 - ALPHA_MIND - INFO - 2020-01-16 00:00:00 full re-balance\n",
"2020-11-15 02:48:13,976 - ALPHA_MIND - INFO - 2020-01-16 00:00:00 is finished\n",
"2020-11-15 02:48:13,987 - ALPHA_MIND - INFO - 2020-02-07 00:00:00: 300\n",
"2020-11-15 02:48:13,992 - ALPHA_MIND - WARNING - winsorize_normal normally should not be done after neutralize\n",
"2020-11-15 02:48:13,994 - ALPHA_MIND - INFO - 2020-02-07 00:00:00 full re-balance\n",
"2020-11-15 02:48:14,019 - ALPHA_MIND - INFO - 2020-02-07 00:00:00 is finished\n",
"2020-11-15 02:48:14,027 - ALPHA_MIND - INFO - 2020-02-21 00:00:00: 300\n",
"2020-11-15 02:48:14,032 - ALPHA_MIND - WARNING - winsorize_normal normally should not be done after neutralize\n",
"2020-11-15 02:48:14,034 - ALPHA_MIND - INFO - 2020-02-21 00:00:00 full re-balance\n",
"2020-11-15 02:48:14,062 - ALPHA_MIND - INFO - 2020-02-21 00:00:00 is finished\n",
"2020-11-15 02:48:15,881 - ALPHA_MIND - INFO - 2020-01-02 00:00:00: 299\n",
"2020-11-15 02:48:15,885 - ALPHA_MIND - WARNING - winsorize_normal normally should not be done after neutralize\n",
"2020-11-15 02:48:15,888 - ALPHA_MIND - INFO - 2020-01-02 00:00:00 full re-balance\n",
"2020-11-15 02:48:15,918 - ALPHA_MIND - INFO - 2020-01-02 00:00:00 is finished\n",
"2020-11-15 02:48:15,927 - ALPHA_MIND - INFO - 2020-01-16 00:00:00: 300\n",
"2020-11-15 02:48:15,931 - ALPHA_MIND - WARNING - winsorize_normal normally should not be done after neutralize\n",
"2020-11-15 02:48:15,934 - ALPHA_MIND - INFO - 2020-01-16 00:00:00 full re-balance\n",
"2020-11-15 02:48:15,964 - ALPHA_MIND - INFO - 2020-01-16 00:00:00 is finished\n",
"2020-11-15 02:48:15,973 - ALPHA_MIND - INFO - 2020-02-07 00:00:00: 300\n",
"2020-11-15 02:48:15,978 - ALPHA_MIND - WARNING - winsorize_normal normally should not be done after neutralize\n",
"2020-11-15 02:48:15,982 - ALPHA_MIND - INFO - 2020-02-07 00:00:00 full re-balance\n",
"2020-11-15 02:48:16,007 - ALPHA_MIND - INFO - 2020-02-07 00:00:00 is finished\n",
"2020-11-15 02:48:16,016 - ALPHA_MIND - INFO - 2020-02-21 00:00:00: 300\n",
"2020-11-15 02:48:16,022 - ALPHA_MIND - WARNING - winsorize_normal normally should not be done after neutralize\n",
"2020-11-15 02:48:16,025 - ALPHA_MIND - INFO - 2020-02-21 00:00:00 full re-balance\n",
"2020-11-15 02:48:16,055 - ALPHA_MIND - INFO - 2020-02-21 00:00:00 is finished\n",
"2020-11-15 02:48:17,917 - ALPHA_MIND - INFO - 2020-01-02 00:00:00: 300\n",
"2020-11-15 02:48:17,921 - ALPHA_MIND - WARNING - winsorize_normal normally should not be done after neutralize\n",
"2020-11-15 02:48:17,924 - ALPHA_MIND - INFO - 2020-01-02 00:00:00 full re-balance\n",
"2020-11-15 02:48:17,954 - ALPHA_MIND - INFO - 2020-01-02 00:00:00 is finished\n",
"2020-11-15 02:48:17,962 - ALPHA_MIND - INFO - 2020-01-16 00:00:00: 300\n",
"2020-11-15 02:48:17,967 - ALPHA_MIND - WARNING - winsorize_normal normally should not be done after neutralize\n",
"2020-11-15 02:48:17,969 - ALPHA_MIND - INFO - 2020-01-16 00:00:00 full re-balance\n",
"2020-11-15 02:48:17,995 - ALPHA_MIND - INFO - 2020-01-16 00:00:00 is finished\n",
"2020-11-15 02:48:18,003 - ALPHA_MIND - INFO - 2020-02-07 00:00:00: 300\n",
"2020-11-15 02:48:18,008 - ALPHA_MIND - WARNING - winsorize_normal normally should not be done after neutralize\n",
"2020-11-15 02:48:18,010 - ALPHA_MIND - INFO - 2020-02-07 00:00:00 full re-balance\n",
"2020-11-15 02:48:18,034 - ALPHA_MIND - INFO - 2020-02-07 00:00:00 is finished\n",
"2020-11-15 02:48:18,041 - ALPHA_MIND - INFO - 2020-02-21 00:00:00: 300\n",
"2020-11-15 02:48:18,046 - ALPHA_MIND - WARNING - winsorize_normal normally should not be done after neutralize\n",
"2020-11-15 02:48:18,048 - ALPHA_MIND - INFO - 2020-02-21 00:00:00 full re-balance\n",
"2020-11-15 02:48:18,078 - ALPHA_MIND - INFO - 2020-02-21 00:00:00 is finished\n"
] ]
} }
], ],
...@@ -277,7 +331,7 @@ ...@@ -277,7 +331,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": 7,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
...@@ -290,7 +344,7 @@ ...@@ -290,7 +344,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": 9,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
...@@ -359,4 +413,4 @@ ...@@ -359,4 +413,4 @@
}, },
"nbformat": 4, "nbformat": 4,
"nbformat_minor": 4 "nbformat_minor": 4
} }
\ No newline at end of file
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 1, "execution_count": 9,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
...@@ -32,31 +32,20 @@ ...@@ -32,31 +32,20 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 2, "execution_count": 14,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [],
{
"ename": "AttributeError",
"evalue": "'SqlEngine' object has no attribute 'fetch_factor'",
"output_type": "error",
"traceback": [
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)",
"\u001b[1;32m<ipython-input-2-f6a26cae2a7b>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m 7\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 8\u001b[0m \u001b[0mrisk_cov\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mrisk_exposure\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mengine\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfetch_risk_model\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mref_date\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcodes\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 9\u001b[1;33m \u001b[0mfactor\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mengine\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfetch_factor\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mref_date\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;34m'EPS'\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcodes\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 10\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 11\u001b[0m \u001b[0mtotal_data\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpd\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmerge\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfactor\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mrisk_exposure\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mon\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;34m'code'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdropna\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mAttributeError\u001b[0m: 'SqlEngine' object has no attribute 'fetch_factor'"
]
}
],
"source": [ "source": [
"risk_penlty = 0.5\n", "risk_penlty = 0.5\n",
"ref_date = '2018-02-08'\n", "ref_date = '2020-02-21'\n",
"factor_name = \"EMA5D\"\n",
"\n", "\n",
"engine = SqlEngine(os.environ['DB_URI'])\n", "engine = SqlEngine(os.environ['DB_URI'])\n",
"universe = Universe('ashare_ex')\n", "universe = Universe('hs300')\n",
"codes = engine.fetch_codes(ref_date, universe)\n", "codes = engine.fetch_codes(ref_date, universe)\n",
"\n", "\n",
"risk_cov, risk_exposure = engine.fetch_risk_model(ref_date, codes)\n", "risk_cov, risk_exposure = engine.fetch_risk_model(ref_date, codes)\n",
"factor = engine.fetch_factor(ref_date, 'EPS', codes)\n", "factor = engine.fetch_factor(ref_date, factor_name, codes)\n",
"\n", "\n",
"total_data = pd.merge(factor, risk_exposure, on='code').dropna()\n", "total_data = pd.merge(factor, risk_exposure, on='code').dropna()\n",
"all_styles = risk_styles + industry_styles + macro_styles\n", "all_styles = risk_styles + industry_styles + macro_styles\n",
...@@ -66,12 +55,12 @@ ...@@ -66,12 +55,12 @@
"risk_cov_values = risk_cov[all_styles].values\n", "risk_cov_values = risk_cov[all_styles].values\n",
"\n", "\n",
"sec_cov_values_full = risk_exposure_values @ risk_cov_values @ risk_exposure_values.T / 10000 + np.diag(special_risk_values ** 2) / 10000\n", "sec_cov_values_full = risk_exposure_values @ risk_cov_values @ risk_exposure_values.T / 10000 + np.diag(special_risk_values ** 2) / 10000\n",
"signal_full = total_data['EPS'].values" "signal_full = total_data[factor_name].values"
] ]
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": 15,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
...@@ -91,9 +80,25 @@ ...@@ -91,9 +80,25 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": 18,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Wall time: 976 µs\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"D:\\ProgramData\\Anaconda3\\envs\\alpha-mind\\lib\\site-packages\\ipykernel\\ipkernel.py:287: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.\n",
" and should_run_async(code)\n"
]
}
],
"source": [ "source": [
"%%time\n", "%%time\n",
"w = Variable(n)\n", "w = Variable(n)\n",
...@@ -101,9 +106,9 @@ ...@@ -101,9 +106,9 @@
"lbound = 0.\n", "lbound = 0.\n",
"ubound = 1. / n * 20\n", "ubound = 1. / n * 20\n",
"\n", "\n",
"risk = sum_squares(multiply(special_risk_values[:n] / 100., w)) + quad_form((w.T * risk_exposure_values[:n]).T, risk_cov_values[:n, :n] / 10000.)\n", "risk = sum_squares(multiply(special_risk_values[:n] / 100., w)) + quad_form((w.T @ risk_exposure_values[:n]).T, risk_cov_values[:n, :n] / 10000.)\n",
"\n", "\n",
"objective = Minimize(risk_penlty * risk - signal * w)\n", "objective = Minimize(risk_penlty * risk - signal @ w)\n",
"constraints = [w >= lbound,\n", "constraints = [w >= lbound,\n",
" w <= ubound,\n", " w <= ubound,\n",
" sum(w) == 1,]\n", " sum(w) == 1,]\n",
...@@ -113,19 +118,52 @@ ...@@ -113,19 +118,52 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 19,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"ename": "NameError", "name": "stdout",
"evalue": "name 'prob' is not defined", "output_type": "stream",
"output_type": "error", "text": [
"traceback": [ "-----------------------------------------------------------------\n",
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", " OSQP v0.6.0 - Operator Splitting QP Solver\n",
"\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", " (c) Bartolomeo Stellato, Goran Banjac\n",
"\u001b[1;32m<timed eval>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n", " University of Oxford - Stanford University 2019\n",
"\u001b[1;31mNameError\u001b[0m: name 'prob' is not defined" "-----------------------------------------------------------------\n",
"problem: variables n = 439, constraints m = 640\n",
" nnz(P) + nnz(A) = 4419\n",
"settings: linear system solver = qdldl,\n",
" eps_abs = 1.0e-05, eps_rel = 1.0e-05,\n",
" eps_prim_inf = 1.0e-04, eps_dual_inf = 1.0e-04,\n",
" rho = 1.00e-01 (adaptive),\n",
" sigma = 1.00e-06, alpha = 1.60, max_iter = 10000\n",
" check_termination: on (interval 25),\n",
" scaling: on, scaled_termination: off\n",
" warm start: on, polish: on, time_limit: off\n",
"\n",
"iter objective pri res dua res rho time\n",
" 1 -7.8878e+03 4.61e+00 6.68e+04 1.00e-01 1.04e-03s\n",
" 125 -2.4830e+02 3.58e-07 2.76e-05 5.82e-01 3.81e-03s\n",
"\n",
"status: solved\n",
"solution polish: unsuccessful\n",
"number of iterations: 125\n",
"optimal objective: -248.2989\n",
"run time: 4.41e-03s\n",
"optimal rho estimate: 1.87e+00\n",
"\n",
"Wall time: 42 ms\n"
] ]
},
{
"data": {
"text/plain": [
"-248.29894124530716"
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
} }
], ],
"source": [ "source": [
...@@ -135,19 +173,18 @@ ...@@ -135,19 +173,18 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 4, "execution_count": 20,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"ename": "NameError", "data": {
"evalue": "name 'prob' is not defined", "text/plain": [
"output_type": "error", "('optimal', -248.29894124530716)"
"traceback": [ ]
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", },
"\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", "execution_count": 20,
"\u001b[1;32m<ipython-input-4-10ee360ecec6>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mprob\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstatus\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mprob\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mvalue\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "metadata": {},
"\u001b[1;31mNameError\u001b[0m: name 'prob' is not defined" "output_type": "execute_result"
]
} }
], ],
"source": [ "source": [
...@@ -156,19 +193,46 @@ ...@@ -156,19 +193,46 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 5, "execution_count": 21,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"ename": "NameError", "name": "stdout",
"evalue": "name 'prob' is not defined", "output_type": "stream",
"output_type": "error", "text": [
"traceback": [ "\n",
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "ECOS 2.0.7 - (C) embotech GmbH, Zurich Switzerland, 2012-15. Web: www.embotech.com/ECOS\n",
"\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", "\n",
"\u001b[1;32m<timed eval>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n", "It pcost dcost gap pres dres k/t mu step sigma IR | BT\n",
"\u001b[1;31mNameError\u001b[0m: name 'prob' is not defined" " 0 -2.156e+01 -1.165e+04 +2e+05 9e-01 2e-02 1e+00 6e+02 --- --- 1 1 - | - - \n",
" 1 +3.001e+02 -4.385e+03 +2e+05 3e-01 6e-03 2e+01 6e+02 0.1191 5e-01 2 2 2 | 0 0\n",
" 2 -2.457e+03 -3.271e+04 +2e+05 2e+00 4e-02 2e+02 6e+02 0.0130 1e+00 2 2 3 | 0 0\n",
" 3 -7.245e+02 -3.200e+03 +2e+05 3e-01 5e-03 1e+03 6e+02 0.1239 9e-01 2 2 2 | 0 0\n",
" 4 -3.144e+02 -5.230e+02 +6e+04 4e-02 5e-04 2e+02 2e+02 0.8185 2e-01 2 2 2 | 0 0\n",
" 5 -2.573e+02 -2.730e+02 +5e+03 3e-03 4e-05 2e+01 2e+01 0.9090 3e-03 1 2 2 | 0 0\n",
" 6 -2.493e+02 -2.522e+02 +8e+02 5e-04 6e-06 3e+00 3e+00 0.8565 2e-02 1 2 2 | 0 0\n",
" 7 -2.483e+02 -2.485e+02 +3e+01 2e-05 2e-07 4e-02 8e-02 0.9855 2e-02 1 2 2 | 0 0\n",
" 8 -2.483e+02 -2.483e+02 +2e+00 1e-06 1e-08 3e-03 6e-03 0.9240 1e-03 1 1 1 | 0 0\n",
" 9 -2.483e+02 -2.483e+02 +9e-02 4e-08 5e-10 3e-05 2e-04 0.9890 2e-02 1 2 2 | 0 0\n",
"10 -2.483e+02 -2.483e+02 +1e-03 5e-10 5e-12 4e-07 2e-06 0.9890 1e-04 1 1 1 | 0 0\n",
"11 -2.483e+02 -2.483e+02 +1e-05 8e-12 8e-14 5e-09 4e-08 0.9853 1e-04 1 1 1 | 0 0\n",
"12 -2.483e+02 -2.483e+02 +3e-07 5e-13 2e-15 1e-10 8e-10 0.9775 1e-04 1 1 1 | 0 0\n",
"\n",
"OPTIMAL (within feastol=5.3e-13, reltol=1.3e-09, abstol=3.2e-07).\n",
"Runtime: 0.008978 seconds.\n",
"\n",
"Wall time: 40 ms\n"
] ]
},
{
"data": {
"text/plain": [
"-248.2989614228091"
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
} }
], ],
"source": [ "source": [
...@@ -178,16 +242,16 @@ ...@@ -178,16 +242,16 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 15, "execution_count": 22,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"('optimal', -2.400328236659518)" "('optimal', -248.2989614228091)"
] ]
}, },
"execution_count": 15, "execution_count": 22,
"metadata": {}, "metadata": {},
"output_type": "execute_result" "output_type": "execute_result"
} }
...@@ -198,7 +262,7 @@ ...@@ -198,7 +262,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 16, "execution_count": 23,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
...@@ -206,22 +270,22 @@ ...@@ -206,22 +270,22 @@
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
" pcost dcost gap pres dres\n", " pcost dcost gap pres dres\n",
" 0: -4.0275e+01 -8.9373e+01 8e+03 6e+01 6e-16\n", " 0: -6.5797e+05 -3.3860e+04 1e+08 7e+03 7e-16\n",
" 1: -2.7029e+00 -8.3780e+01 2e+02 1e+00 2e-15\n", " 1: -1.7446e+04 -1.0601e+04 2e+06 1e+02 3e-14\n",
" 2: -1.3699e+00 -2.0914e+01 2e+01 3e-15 3e-15\n", " 2: -4.0149e+02 -1.0036e+04 3e+04 2e+00 5e-14\n",
" 3: -1.6193e+00 -6.3167e+00 5e+00 5e-16 2e-15\n", " 3: -1.8099e+02 -3.2793e+03 3e+03 1e-15 4e-14\n",
" 4: -1.8992e+00 -4.2870e+00 2e+00 5e-16 1e-15\n", " 4: -1.9534e+02 -7.5624e+02 6e+02 2e-16 6e-15\n",
" 5: -2.1306e+00 -3.2594e+00 1e+00 4e-16 8e-16\n", " 5: -2.1878e+02 -3.6280e+02 1e+02 2e-16 4e-16\n",
" 6: -2.1625e+00 -2.9783e+00 8e-01 3e-16 6e-16\n", " 6: -2.2458e+02 -3.2078e+02 1e+02 2e-16 4e-16\n",
" 7: -2.2529e+00 -2.6835e+00 4e-01 3e-16 6e-16\n", " 7: -2.3361e+02 -2.9012e+02 6e+01 2e-16 3e-16\n",
" 8: -2.3100e+00 -2.5413e+00 2e-01 1e-15 5e-16\n", " 8: -2.3634e+02 -2.7977e+02 4e+01 2e-16 3e-16\n",
" 9: -2.3407e+00 -2.4723e+00 1e-01 8e-16 5e-16\n", " 9: -2.3759e+02 -2.6601e+02 3e+01 2e-16 2e-16\n",
"10: -2.3953e+00 -2.4100e+00 1e-02 4e-16 1e-15\n", "10: -2.4290e+02 -2.5586e+02 1e+01 2e-16 3e-16\n",
"11: -2.4002e+00 -2.4005e+00 2e-04 2e-16 9e-16\n", "11: -2.4774e+02 -2.4901e+02 1e+00 2e-16 4e-16\n",
"12: -2.4003e+00 -2.4003e+00 2e-06 2e-16 9e-16\n", "12: -2.4829e+02 -2.4831e+02 1e-02 2e-16 4e-16\n",
"13: -2.4003e+00 -2.4003e+00 2e-08 2e-16 9e-16\n", "13: -2.4830e+02 -2.4830e+02 1e-04 2e-16 1e-15\n",
"Optimal solution found.\n", "Optimal solution found.\n",
"Wall time: 23.9 ms\n" "Wall time: 62 ms\n"
] ]
} }
], ],
...@@ -252,15 +316,25 @@ ...@@ -252,15 +316,25 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 17, "execution_count": 24,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"name": "stdout", "name": "stdout",
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Wall time: 20.9 ms\n" "Wall time: 18 ms\n"
] ]
},
{
"data": {
"text/plain": [
"0"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
} }
], ],
"source": [ "source": [
...@@ -295,7 +369,7 @@ ...@@ -295,7 +369,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 18, "execution_count": 25,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
...@@ -304,7 +378,7 @@ ...@@ -304,7 +378,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 19, "execution_count": 26,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
...@@ -316,9 +390,18 @@ ...@@ -316,9 +390,18 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 20, "execution_count": 36,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"D:\\ProgramData\\Anaconda3\\envs\\alpha-mind\\lib\\site-packages\\ipykernel\\ipkernel.py:287: DeprecationWarning: `should_run_async` will not call `transform_cell` automatically in the future. Please pass the result to `transformed_cell` argument and any exception that happen during thetransform in `preprocessing_exc_tuple` in IPython 7.17 and above.\n",
" and should_run_async(code)\n"
]
}
],
"source": [ "source": [
"def cvxpy(n):\n", "def cvxpy(n):\n",
" w = Variable(n)\n", " w = Variable(n)\n",
...@@ -326,9 +409,9 @@ ...@@ -326,9 +409,9 @@
" lbound = 0.\n", " lbound = 0.\n",
" ubound = 0.01\n", " ubound = 0.01\n",
" \n", " \n",
" risk = sum_squares(multiply(special_risk_values[:n] / 100., w)) + quad_form((w.T * risk_exposure_values[:n]).T, risk_cov_values[:n, :n] / 10000.)\n", " risk = sum_squares(multiply(special_risk_values[:n] / 100., w)) + quad_form((w.T @ risk_exposure_values[:n]).T, risk_cov_values[:n, :n] / 10000.)\n",
"\n", "\n",
" objective = Minimize(risk_penlty * risk - signal * w)\n", " objective = Minimize(risk_penlty * risk - signal @ w)\n",
" constraints = [w >= lbound,\n", " constraints = [w >= lbound,\n",
" w <= ubound,\n", " w <= ubound,\n",
" sum(w) == 1,]\n", " sum(w) == 1,]\n",
...@@ -340,7 +423,7 @@ ...@@ -340,7 +423,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 21, "execution_count": 37,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
...@@ -372,7 +455,7 @@ ...@@ -372,7 +455,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 22, "execution_count": 38,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
...@@ -391,7 +474,7 @@ ...@@ -391,7 +474,7 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 23, "execution_count": 39,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
...@@ -399,55 +482,14 @@ ...@@ -399,55 +482,14 @@
"output_type": "stream", "output_type": "stream",
"text": [ "text": [
"Scale(n) cvxpy cvxopt ipopt\n", "Scale(n) cvxpy cvxopt ipopt\n",
"200 0.0340 0.0109 0.0120\n", "100 0.0230 0.0200 0.0050\n",
"400 0.0399 0.0469 0.0199\n", "200 0.0290 0.0360 0.0110\n",
"600 0.0519 0.1606 0.0319\n", "300 0.0360 0.0500 0.0150\n"
"800 0.0708 0.5037 0.0519\n",
"1000 0.1027 0.9594 0.0469\n",
"1200 0.1406 1.6586 0.0539\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"D:\\ProgramData\\anaconda3\\lib\\site-packages\\cvxpy-1.0.10-py3.6-win-amd64.egg\\cvxpy\\problems\\problem.py:614: RuntimeWarning: overflow encountered in long_scalars\n",
" if self.max_big_small_squared < big*small**2:\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"1400 0.1386 2.7945 0.0728\n",
"1600 0.1586 3.8437 0.0987\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"D:\\ProgramData\\anaconda3\\lib\\site-packages\\cvxpy-1.0.10-py3.6-win-amd64.egg\\cvxpy\\problems\\problem.py:615: RuntimeWarning: overflow encountered in long_scalars\n",
" self.max_big_small_squared = big*small**2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"1800 0.2224 8.4165 0.1885\n",
"2000 0.3022 10.5777 0.1905\n",
"2200 0.3201 15.0518 0.1676\n",
"2400 0.3282 17.1641 0.2045\n",
"2600 0.3391 23.3546 0.1985\n",
"2800 0.4807 29.7235 0.2424\n",
"3000 0.4199 39.5318 0.2804\n",
"3200 0.5067 53.5702 0.2586\n"
] ]
} }
], ],
"source": [ "source": [
"n_steps = list(range(200, 3201, 200))\n", "n_steps = list(range(100, 301, 100))\n",
"cvxpy_times = [None] * len(n_steps)\n", "cvxpy_times = [None] * len(n_steps)\n",
"cvxopt_times = [None] * len(n_steps)\n", "cvxopt_times = [None] * len(n_steps)\n",
"ipopt_times = [None] * len(n_steps)\n", "ipopt_times = [None] * len(n_steps)\n",
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
{ {
"data": { "data": {
"text/plain": [ "text/plain": [
"datetime.datetime(2020, 11, 14, 15, 58, 13, 404266)" "datetime.datetime(2020, 11, 15, 2, 56, 3, 86969)"
] ]
}, },
"execution_count": 1, "execution_count": 1,
...@@ -43,10 +43,10 @@ ...@@ -43,10 +43,10 @@
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"start_date = '2017-04-10'\n", "start_date = '2020-01-01'\n",
"end_date = '2018-04-09'\n", "end_date = '2020-02-21'\n",
"\n", "\n",
"freq = '5b'\n", "freq = '10b'\n",
"horizon = map_freq(freq)\n", "horizon = map_freq(freq)\n",
"neutralized_risk = risk_styles + industry_styles\n", "neutralized_risk = risk_styles + industry_styles\n",
"universe = Universe('zz500')\n", "universe = Universe('zz500')\n",
...@@ -64,13 +64,13 @@ ...@@ -64,13 +64,13 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 3, "execution_count": 5,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [],
"source": [ "source": [
"alpha_factors = {\n", "alpha_factors = {\n",
" 'f01': LAST('EPS'),\n", " 'f01': LAST('EMA5D'),\n",
" 'f02': LAST('ROE')\n", " 'f02': LAST('EMV6D')\n",
" }\n", " }\n",
"\n", "\n",
"weights = dict(f01=1.0,\n", "weights = dict(f01=1.0,\n",
...@@ -96,23 +96,21 @@ ...@@ -96,23 +96,21 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 4, "execution_count": 6,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"ename": "AttributeError", "name": "stderr",
"evalue": "'SqlEngine' object has no attribute 'fetch_factor_range'", "output_type": "stream",
"output_type": "error", "text": [
"traceback": [ "D:\\ProgramData\\Anaconda3\\envs\\alpha-mind\\lib\\site-packages\\alpha_mind-0.2.3-py3.7-win-amd64.egg\\alphamind\\model\\data_preparing.py:412: FutureWarning: DataFrame.mean and DataFrame.median with numeric_only=None will include datetime64 and datetime64tz columns in a future version.\n",
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", " lambda x: x.fillna(x.median())).reset_index(\n",
"\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", "D:\\ProgramData\\Anaconda3\\envs\\alpha-mind\\lib\\site-packages\\alpha_mind-0.2.3-py3.7-win-amd64.egg\\alphamind\\model\\data_preparing.py:412: FutureWarning: DataFrame.mean and DataFrame.median with numeric_only=None will include datetime64 and datetime64tz columns in a future version.\n",
"\u001b[1;32m<ipython-input-4-fe9f95d31cfa>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;31m# %%time\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mpredicts\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[0mpredict_worker\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0md\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstrftime\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'%Y-%m-%d'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0malpha_model\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0md\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mref_dates\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", " lambda x: x.fillna(x.median())).reset_index(\n",
"\u001b[1;32m<ipython-input-4-fe9f95d31cfa>\u001b[0m in \u001b[0;36m<listcomp>\u001b[1;34m(.0)\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[1;31m# %%time\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mpredicts\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[0mpredict_worker\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0md\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstrftime\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'%Y-%m-%d'\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0malpha_model\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0md\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mref_dates\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "D:\\ProgramData\\Anaconda3\\envs\\alpha-mind\\lib\\site-packages\\alpha_mind-0.2.3-py3.7-win-amd64.egg\\alphamind\\model\\data_preparing.py:412: FutureWarning: DataFrame.mean and DataFrame.median with numeric_only=None will include datetime64 and datetime64tz columns in a future version.\n",
"\u001b[1;32m<ipython-input-3-4e15561bc4f5>\u001b[0m in \u001b[0;36mpredict_worker\u001b[1;34m(params)\u001b[0m\n\u001b[0;32m 21\u001b[0m data_source=data_source)\n\u001b[0;32m 22\u001b[0m \u001b[0mref_date\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmodel\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mparams\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 23\u001b[1;33m \u001b[0mer\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0m_\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpredict_by_model\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mref_date\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmodel\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdata_meta\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 24\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mer\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", " lambda x: x.fillna(x.median())).reset_index(\n",
"\u001b[1;32mD:\\ProgramData\\Anaconda3\\envs\\alpha-mind\\lib\\site-packages\\alpha_mind-0.2.3-py3.7-win-amd64.egg\\alphamind\\model\\composer.py\u001b[0m in \u001b[0;36mpredict_by_model\u001b[1;34m(ref_date, alpha_model, data_meta, x_values, codes)\u001b[0m\n\u001b[0;32m 165\u001b[0m codes: Iterable[int] = None):\n\u001b[0;32m 166\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mx_values\u001b[0m \u001b[1;32mis\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 167\u001b[1;33m \u001b[0mpredict_data\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mdata_meta\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfetch_predict_data\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mref_date\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0malpha_model\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 168\u001b[0m \u001b[0mcodes\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mx_values\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpredict_data\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'predict'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'code'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mpredict_data\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'predict'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'x'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 169\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", "D:\\ProgramData\\Anaconda3\\envs\\alpha-mind\\lib\\site-packages\\alpha_mind-0.2.3-py3.7-win-amd64.egg\\alphamind\\model\\data_preparing.py:412: FutureWarning: DataFrame.mean and DataFrame.median with numeric_only=None will include datetime64 and datetime64tz columns in a future version.\n",
"\u001b[1;32mD:\\ProgramData\\Anaconda3\\envs\\alpha-mind\\lib\\site-packages\\alpha_mind-0.2.3-py3.7-win-amd64.egg\\alphamind\\model\\composer.py\u001b[0m in \u001b[0;36mfetch_predict_data\u001b[1;34m(self, ref_date, alpha_model)\u001b[0m\n\u001b[0;32m 140\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwarm_start\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 141\u001b[0m \u001b[0mfillna\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;32mTrue\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 142\u001b[1;33m fit_target=alpha_model.fit_target)\n\u001b[0m\u001b[0;32m 143\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 144\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", " lambda x: x.fillna(x.median())).reset_index(\n"
"\u001b[1;32mD:\\ProgramData\\Anaconda3\\envs\\alpha-mind\\lib\\site-packages\\alpha_mind-0.2.3-py3.7-win-amd64.egg\\alphamind\\model\\data_preparing.py\u001b[0m in \u001b[0;36mfetch_predict_phase\u001b[1;34m(engine, alpha_factors, ref_date, frequency, universe, batch, neutralized_risk, risk_model, pre_process, post_process, warm_start, fillna, fit_target)\u001b[0m\n\u001b[0;32m 406\u001b[0m \u001b[0mhorizon\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mmap_freq\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfrequency\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 407\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 408\u001b[1;33m \u001b[0mfactor_df\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mengine\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfetch_factor_range\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0muniverse\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfactors\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mtransformer\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdates\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mdates\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 409\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 410\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mfillna\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
"\u001b[1;31mAttributeError\u001b[0m: 'SqlEngine' object has no attribute 'fetch_factor_range'"
] ]
} }
], ],
...@@ -123,18 +121,21 @@ ...@@ -123,18 +121,21 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": 5, "execution_count": 7,
"metadata": {}, "metadata": {},
"outputs": [ "outputs": [
{ {
"ename": "AttributeError", "name": "stderr",
"evalue": "'SqlEngine' object has no attribute 'fetch_industry_matrix_range'", "output_type": "stream",
"output_type": "error", "text": [
"traceback": [ "2020-11-15 02:56:56,585 - ALPHA_MIND - INFO - 2020-01-02 full re-balance: 500\n",
"\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "2020-11-15 02:56:57,007 - ALPHA_MIND - INFO - 2020-01-02 is finished\n",
"\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", "2020-11-15 02:56:57,011 - ALPHA_MIND - INFO - 2020-01-16 full re-balance: 500\n",
"\u001b[1;32m<ipython-input-5-33f95fe45d6f>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m 1\u001b[0m \u001b[0mindustry_names\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mindustry_list\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mindustry_name\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mindustry_level\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0mindustry_total\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mengine\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfetch_industry_matrix_range\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0muniverse\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdates\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mref_dates\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcategory\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mindustry_name\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mlevel\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mindustry_level\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 3\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[0mprevious_pos\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpd\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mDataFrame\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[0mrets\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m[\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "2020-11-15 02:56:57,289 - ALPHA_MIND - INFO - 2020-01-16 is finished\n",
"\u001b[1;31mAttributeError\u001b[0m: 'SqlEngine' object has no attribute 'fetch_industry_matrix_range'" "2020-11-15 02:56:57,293 - ALPHA_MIND - INFO - 2020-02-07 full re-balance: 500\n",
"2020-11-15 02:56:57,493 - ALPHA_MIND - INFO - 2020-02-07 is finished\n",
"2020-11-15 02:56:57,496 - ALPHA_MIND - INFO - 2020-02-21 full re-balance: 500\n",
"2020-11-15 02:56:57,737 - ALPHA_MIND - INFO - 2020-02-21 is finished\n"
] ]
} }
], ],
...@@ -186,9 +187,30 @@ ...@@ -186,9 +187,30 @@
}, },
{ {
"cell_type": "code", "cell_type": "code",
"execution_count": null, "execution_count": 8,
"metadata": {}, "metadata": {},
"outputs": [], "outputs": [
{
"data": {
"text/plain": [
"<AxesSubplot:title={'center':'Fixed freq rebalanced: 10b'}>"
]
},
"execution_count": 8,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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b4KCgsy//vWvStv07Nmz0tds6dKlpl27dmbp0qUnPYYjTnS8s2bNMoApKSmp9PnHHnvMdOzYsVLd/fv3r7TN2LFjTVxcXLXeX0TkdNWeZQlEpNbr06cPb731Vvnjk62MMnDgQB599FH+8pe/cN999zFkyJDy59LS0liyZAnTpk075nWbNm2iVatW7Nq165iJqv379+ejjz46rdp79uyJw1HxR8y0tDRWrFhBeHh4pe2KiorYtGkTABs2bGDw4MHH1FAdHTp0qLTvtLQ09uzZQ8OGDSttV1JSQkhISKXPXXTRReUf+/v707t3b9avX1/+uX//+9+88cYbbNu2jYKCAtxu90mHgdi2zd///nfee+89MjIyKC4upqysjBYtWlTarn379gQFBZU/jomJqTS0ZsWKFUycOPG477Fv3z62b9/OI488Uukqvjn8F5b09HSCgoIoKSk57td17ty55Y979+7NTz/9dMLjOReO7jlAv379eO6558jNzSUiIuK81iIi9YeCvIicNyEhIdVeJtDj8ZCSkoKfnx+bN2/GGINlWYA3WD7++OPcdtttx7wuOjr6nIxNDgsLq/TYtm0GDx583F8mGjRocE7er0OHDsyZM+eYbUNDQ6u93w8++IAHH3yQiRMncumllxIREcEHH3zAE088ccLXvPTSSzz33HNMnjyZ7t2743Q6mTx5Mp9++mml7X45MdiyrErj6E/myNdsypQpDBw48Jjn4+Li2LhxY7X2dbY0a9YMgD179pTPiwDYu3dv+XMiIr6kIC8iNdJf/vIX0tPTSUlJ4YorruDvf/87jz/+OACJiYmsX7/+pL8UxMbGkpqayjXXXFP+uZSUlLNWX2JiIjNnziQuLo7g4ODjbtOxY0dSU1Mrfe50a0hMTOTtt98mIiKCqKiok267ZMkSOnbsCHjXxV+2bFn5Lz3fffcd3bt355FHHinfftu2bSfd33fffceVV17JyJEjyz935K8Op6Jnz5589dVXjBo16pjnmjZtSvPmzfn555+55557jvv6hIQEAgMDSU1NpVOnTuWfP5tf11/WGxQUxJdffllek23bzJs3j3vvvbfStr9cPjU1NZXY2FhdjReRc0qTXUWkxvn222+ZOHEib731Fn369OFf//oXTz75JMuWLQPg6aef5uOPP+aRRx5h9erVbN68mS+++IK77rqLoqIiAB599FGmTJnCO++8w6ZNm3jppZeYN2/eWavxoYcewuPxcP3117No0SK2bdvG4sWLeeKJJ8rD+8MPP8z333/PE088wcaNG5kzZw4vvfTSab3fLbfcwgUXXMA111zDV199xbZt21i6dCnPPffcMcOFJk6cyGeffcaPP/7I/fffz759+8qXWGzXrh1r167l448/ZvPmzUyZMoUPP/zwpO/drl07Fi5cyIIFC9i4cSPjx49n6dKlp3wMTz75JJ9//jmjR4/mhx9+4Oeff2bmzJn8/PPPAEyYMIGXX36ZCRMmsG7dOn7++Wc++ugjfve73wHev1Lcd999jB8/nk8++YSff/6ZP/3pT+WvP2LZsmW0b9++/PvlRNLT01m9ejU7duwAYPXq1axevZr8/HwAIiIiuO+++xg3bhxz585l/fr1jBw5kqKiovKajli9ejV/+ctf2LhxI++++y5Tpkzh0UcfPeUeiYicEh+P0ReReuKOO+4wgwcPPu5zR08wzc7ONnFxcebRRx+ttM0999xjWrVqZXJzc40xxnz33Xdm8ODBJjw83ISGhpr27dubP/zhD+WTQT0ejxk7dqyJjIw0oaGh5oYbbjCTJk067cmud9111zHbbtu2zdx8882mcePGJjAw0MTHx5tbbrnFbNmypXyb//znP6ZVq1YmMDDQ9O7d23z00UfVmux6vF7t37/f3HfffSYmJsYEBASYmJgYM2TIELNy5UpjTMVk148//tj06NHDBAYGmg4dOpivvvqqfB+lpaXm3nvvNY0aNTJOp9PcdNNN5RNwj/jl5M+DBw+aYcOGGafTaVwul3nggQfM+PHjTYsWLU5a8zvvvGN++WPmiy++MH379jXBwcEmIiLCDBgwwGzevLn8+Tlz5pi+ffuakJAQ43Q6TdeuXc1f//rX8ucLCwvNvffeayIiIkxERIS55557zJgxYyp9zY70YcGCBSfssTHerytwzH9Hv660tNT88Y9/NE2bNjVBQUEmKSnJpKWlVdpPixYtzLhx48yIESPKe/T4449XmhwtInIuWMZUcwCjiIicsW3btnHBBRewaNGiak98FREROR4NrRERERERqYUU5EVEREREaiENrRERERERqYV0RV5EREREpBZSkBcRERERqYVq3Q2hdu/e7esSRERERKQOi4mJqXKb1atXM2PGjPI7fQ8ZMqTS82VlZUybNo0t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9qEunptOtxf17dz0y3P5Ed9//z1vvPEG8fHxtGvXju7du+Pn58eXX37JHXfcUd4f27Zxu911Yuy3enHmasTQGmMMc+fO5fvvvychIYEPPviAhQsXUlBQUL7NHXfcwTvvvFP+uGXLljzwwAOEh4dXmuRX2384qBdeZ9qHI3++TkhIqPU/KM/W98S1115bb35Qni2/7P3777/PwoULKS4uLl9pZP/+/ZSWlpaPAa6L/x5BvTjiTPtQl89Np/s9UV/OTSc6lx86dAiAiIgInnrqKcaPH4/L5WLBggU0btyYBx98sFK/HA5HrQ+u6sXZUyOCvGVZrF+/nuHDh9O3b1/uuOMOtm/fzpo1a8q36d27NzExMXzyyScA/PDDDwCVJvjVBeqF15n2wc/Pzyd1nwv6nvCdE/V+9erV5dvs2LGDZs2aERoaSk5ODlu3bgXqXu/VC68z7UN9ODfVt++J6jpRv1atWgVAp06diI+Px8/Pj/j4eIqLiwkODsYYU+f6pV6cPT7vxJHfqhISEvjpp58A6NatG82aNWPnzp2V1ki9++67mTVrFvfcc0/5DUPq0hdTvfBSHyqoF75TVe937twJQG5uLoGBgXz++edMmDCB7OxsoG71Xr3wUh8qqBen5mT92rVrV6VzOcCaNWsICgoiMDCw/G63dYV6cXad924c+QIeGZp/5AsSHR1NUVERO3bsAKBjx44UFhaW35Fr27ZtvP766/Tp04fnn3++Tqwpq154qQ8V1AvfOdXel5aWAt61v7/++mv27NnDE088QWJiog+qP7vUCy/1oYJ6cWpO51zudrv57rvveOyxx9i3bx8333xznQit6sW55X++3uinn35i3rx5NG3alKuuuqp8PNyRCXutW7dmx44drFmzhtjYWOLi4sjJyWHz5s0kJCQQHh7O3XffTXx8/Pkq+ZxRL7zUhwrqhe+cbu/T09NJSEjgkksu4aqrrqJz584+PpIzp154qQ8V1ItTc7r92rJlCwkJCURGRnL33XfTvn17Hx/JmVMvzo/z8uvN3r17mT59Op07d2bfvn289957rFy5EqB81Y3o6GhatWrF3r17+eijjwDvhKgmTZoA3jVS60JIUS+81IcK6oXvnEnvmzZtCkCfPn3qREhRL7zUhwrqxak5G+fyTp061Yngql6cP+clyKenpxMbG8uAAQO4/fbbadmyJStWrCi/tfB7773HP//5T1q1asVVV11Feno6jz/+OOHh4XTt2vV8lHjeqBde6kMF9cJ3zqT3Xbp08XH1Z5d64aU+VFAvTo36VUG9OH/OydCa5cuXs3//flq1akXbtm1p3bo1X3zxBfv376dx48a0b9+evXv3kpKSQuvWrdm7dy/Dhw8vv6PdH/7wBzweT61fmgvUiyPUhwrqhe+o9xXUCy/1oYJ6cWrUrwrqhe+c1RtCHThwgNdff53CwkK6dOlCSkoKd9xxB926dePtt9+mUaNGXHfdddi2zeLFi9m7dy/XXHNN+a1069KSQuqFl/pQQb3wHfW+gnrhpT5UUC9OjfpVQb3wvbPavc2bN9OhQweefvppbrzxRq666irmzZsHQIcOHdixYwebNm3C4XDgcrn48ccf6+wXU73wUh8qqBe+o95XUC+81IcK6sWpUb8qqBe+d8Yd/Pbbb1m/fj1lZWVceOGFXHLJJeXPOZ1OYmJiAGjTpg0XXHABb7/9NsXFxezcuZPGjRtTUlLiLaQOfDHVCy/1oYJ64TvqfQX1wkt9qKBenBr1q4J6UbOc1hh5YwwHDx7k5ZdfxrIsmjZtyjfffMOIESNo1KhR+dJCBw4cID8/H4CGDRty9dVXs2/fPl599VX279/PQw89RFBQ0Fk9oPNNvfBSHyqoF76j3ldQL7zUhwrqxalRvyqoFzWYOUUej8cYY8yuXbvMlClTyj83ffp088ILL1Ta5rnnnjNr1qwxxhhz8OBBY4wxbrfbFBYWnurb1kjqhZf6UEG98B31voJ64aU+VFAvTo36VUG9qNmq/XcN27Z59913effdd9mwYQO7d+8u/7OIw+FgxIgR/Pzzz2zYsAGHw4Hb7SYiIoKYmBj+85//8Le//Y38/Hz8/PwICQk5Z7+YnA/qhZf6UEG98B31voJ64aU+VFAvTo36VUG9qB2qFeQ3bNjA448/TkFBAdHR0cyePRt/f3/Wr19Penq6d0cOB8OGDeP9998HoLS0lG+//Zann36aoqIinnzyyfK7etVm6oWX+lBBvfAd9b6CeuGlPlRQL06N+lVBvag9qjVG3rIsrrvuuvIJDdu2bSMrK4vhw4fz73//m+effx7btunduzfr1q0jOzubAwcOcPHFF3PttdfSsmXLc3kM55V64aU+VFAvfEe9r6BeeKkPFdSLU6N+VVAvao9qXZFv1aoVF110EbZtA9CuXTv279/PgAEDsG2bzz//HIfDQXZ2Ng6Hg8jISFq3bs1DDz1U576Y6oWX+lBBvfAd9b6CeuGlPlRQL06N+lVBvag9qhXkg4KCCAgIKB8b9cMPPxAREQHAAw88wK5du5g4cSJTpkyhVatWgHeGc12kXnipDxXUC99R7yuoF17qQwX14tSoXxXUi9rjlJafPPKb2aFDh0hMTAQgJCSEm266iZ07dxIVFYXL5QK8f5apy9QLL/WhgnrhO+p9BfXCS32ooF6cGvWrgnpR851SkLcsC7fbjdPpZPv27cycOZPw8HBGjhxJ+/btz1WNNZJ64aU+VFAvfEe9r6BeeKkPFdSLU6N+VVAvar5TDvJbt25l8eLFZGVlMfD/t3fHNgyEQBQFcUBhR0zV9EMNdkCwqQlOsNJMBasX/QCJ5ymttbduu5oWiw5Bi3O0D1osOgQt9ugVtLjf57v5qGnOWcYYpfdeaq1v3ZWCFosOQYtztA9aLDoELfboFbS42/aQBwAAzvv7Z1cAAOAehjwAACRkyAMAQEKGPAAAJGTIAwBAQoY8AAAkZMgDAEBCP03NxTnZ/pMCAAAAAElFTkSuQmCC\n",
"text/plain": [
"<Figure size 864x432 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [ "source": [
"ret_df = pd.DataFrame({'returns': rets, 'turn_over': turn_overs, 'leverage': leverags}, index=ref_dates)\n", "ret_df = pd.DataFrame({'returns': rets, 'turn_over': turn_overs, 'leverage': leverags}, index=ref_dates)\n",
"ret_df.loc[advanceDateByCalendar('china.sse', ref_dates[-1], freq)] = 0.\n", "ret_df.loc[advanceDateByCalendar('china.sse', ref_dates[-1], freq)] = 0.\n",
......
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