# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# > 在本例中，使用公式选股并进行回测

# +
# %matplotlib inline

import os
import datetime as dt
import pandas as pd
import numpy as np
from PyFin.api import *
from alphamind.api import *
from matplotlib import pyplot as plt
# -

# ## 1. 参数设置
# ----------------
#
# * 调仓频率：每周
# * 股票池  ：中证800
# * 起始日  ：2017-05-31
# * 结束日  ：2019-05-31

freq = "1w"
universe = Universe('zz800')
engine = SqlEngine(os.environ['DB_URI'])
start_date = '2017-05-31'
end_date = '2019-05-31'
rebalance_dates = makeSchedule(start_date, end_date, freq, 'china.sse', BizDayConventions.Preceding)

# ## 2. 选股公式
# -----------------------
#
# * 在每个调仓日获取每个行业按照`ETOP`因子排序，最高的3支股票。行业分类使用申万1级

formula = CSTopN(LAST('ETOP'), 3, groups='sw1')

# ## 3. 计算过程
# ----------------

# * 获取因子值以及行业信息

# %%time
factors = engine.fetch_factor_range(universe, {'alpha': formula}, dates=rebalance_dates)
industries = engine.fetch_industry_range(universe, dates=rebalance_dates)

# * 因子选股并且进行获取相关股票每日收益

# %%time
chosen_stks = factors[factors.alpha == 1.]
codes = chosen_stks.code.unique()
stk_returns = engine.fetch_dx_return_range(universe, start_date, end_date)

# * 计算每日调仓结果以及收益

# +
# %%time

ret_dates = np.unique(stk_returns.trade_date)
rebalance_dates = chosen_stks.trade_date.unique()

rtn_groups = stk_returns.groupby('trade_date')
industry_groups = industries.groupby('trade_date')
stks_groups = chosen_stks.groupby('trade_date')

portfolio_rtns = []
portfolios = pd.DataFrame(columns=['code', 'weight', 'industry'])

for ref_date, g in rtn_groups:
    ref_date = ref_date.to_datetime64()
    nearest_date = rebalance_dates[rebalance_dates <= ref_date][-1]
    this_codes = stks_groups.get_group(nearest_date)['code'].tolist()
    
    next_day_rtn = g.loc[g.code.isin(this_codes), 'dx'].values
    portfolio_nd_rtn = np.mean(next_day_rtn)
    portfolio_rtns.append(portfolio_nd_rtn)
    if ref_date in rebalance_dates:
        this_industry = industry_groups.get_group(nearest_date).set_index('code')
        this_df = pd.DataFrame(data={'code': this_codes,
                                     'weight': np.ones(len(this_codes)) * 1. / len(this_codes),
                                     'industry': this_industry.loc[this_codes, 'industry'].values})
        this_df.index =[ref_date] * len(this_codes)
        portfolios = portfolios.append(this_df)

portfolio_rtns = pd.DataFrame({'ret': portfolio_rtns}, index=ret_dates)
# -

# ## 4. 表现展示
# -------------------
#
# ### 4.1 日收益与回撤

from PyFin.Math.Accumulators import MovingDrawdown

# +
# %%time
mv = MovingDrawdown(window=1000, x='ret')
dds = []

for r in portfolio_rtns['ret'].values:
    mv.push({'ret': r})
    dds.append(mv.value)

portfolio_rtns['dd.'] = dds
# -

portfolio_rtns['ret'].cumsum().plot(figsize=(14, 7))
portfolio_rtns['dd.'].plot(kind='area')
plt.legend(['ret', 'dd.'])
plt.ylim([-0.6, 0.3])

# ### 4.2 月度收益

portfolio_rtns['ret'].resample('M').sum().plot(figsize=(14, 7), kind='bar')
plt.legend(['ret'])

# ### 4.3 行业分布

portfolios.reset_index().groupby(['index', 'industry']).count()



StarcoderdataJupyterScriptsDedupFiltered