吾日三省吾身。
以自己喜欢的方式过这一生。
昨天我突然想到这句:“以悦人之心,做悦己的事情”。
你做的事情,要对别人有价值,对更多人有价值,对市场有价值,那么市场会给你回报。这叫“取悦他人”的目标,”悦己“,做你自己认同且喜欢,且擅长的事情。
我们在做一件什么事呢?——低门槛快速实验AI量化策略。
我们知道,因子也好,策略也罢,没有永远有效的圣杯。需要不停地观察市场,不断学习,迭代,这时候,需要一个好用的,低成本的策略研发平台。所以我们做“积木式”,“可视化”的策略开发过程。
前面的文章我们主要是围绕ETF、指数多因子轮动,大类资产配置展开。
今天开始我们正式进行A股股票市场。
记住我们的步骤:数据,因子,策略或模型,回测,分析,迭代。
所以,第一步先搞定数据:从tushare直接下载hs300成份股,我们从沪深300开始。你会说这个成份股是一直在变的,没错,但我们只是用它作为一个基准池子,没有特别的影响。一直来就搞4000-5000支股票,数据量大,没必要。
有了300支的清单,我们需要下载历史复权数据。
脚本在这里,把300支股票历史上全量的“后复权”数据保存到本地h5中。
文件400多M了,可能通过git很难下载了。
import akshare as ak import pandas as pd from engine.config import DATA_DIR, DATA_H5 df_codes = pd.read_csv(DATA_DIR.joinpath('hs300.csv').resolve()) codes = df_codes['con_code'] with pd.HDFStore(DATA_H5.resolve()) as s: for i, code in enumerate(codes): symbol = code code = code[:6] print(i, code) df = ak.stock_zh_a_hist(symbol=code, period="daily", adjust="hfq") df['symbol'] = symbol df.rename(columns={'日期': 'date', '开盘': 'open', '收盘': 'close', '最高': 'high', '最低': 'low', '成交量': 'volume', '换手率': 'turnover'}, inplace=True) df['date'] = pd.to_datetime(df['date']) df.set_index('date', inplace=True) df = df[['symbol', 'open', 'high', 'low', 'close', 'volume', 'turnover']] print(df) s[symbol] = df
拿 指数的多因子试试:
from engine.datafeed.dataloader import Hdf5Dataloader from engine.env import Env from engine.algo import * from engine.config import DATA_H5, DATA_DIR df_codes = pd.read_csv(DATA_DIR.joinpath('hs300.csv').resolve()) codes = df_codes['con_code'] loader = Hdf5Dataloader(codes, start_date="20100101") fields = ['roc(close,20)', 'std(volume,20)', 'bias(close,20)', 'roc(close,5)', 'std(volume,5)', 'bias(close,5)', 'rank(roc_20)+rank(bias_20)+rank(roc_5)+rank(bias_5)-rank(std_20)-rank(std_5)'] names = ['roc_20', 'std_20', 'bias_20', 'roc_5', 'std_5', 'bias_5', 'rank'] df = loader.load(fields=fields, names=names) bench_loader = Hdf5Dataloader(['000300.SH']) e = Env(df=df, benchmarks=bench_loader.load(fields=['slope_pair(high,low,18)', 'zscore(rsrs_18,600)<-0.7'], names=['rsrs_18', 'zscore'])) e.set_algos([ RunDays(days=10), #RunWeekly(), # SelectAll(), #SelectBySignal(buy_rules=[], sell_rules=['ind(roc_20)<-0.08']), SelectTopK(drop_top_n=1, K=10, order_by='rank', b_ascending=False), PickTime(benchmark='000300.SH', signal='zscore'), WeightEqually() ]) e.backtest_loop() e.show_results() #e.save_results()
优化了一下performance计算:
之前我们使用empyrical库来计算,我们可以自己计算,后续我们需要补充多个指标,大家最好熟悉指标的计算公式,当然二者计算是结果是一样的。
import pandas as pd from datetime import datetime class PerformanceUtils(object): def rate2equity(self, df_rates): df = df_rates.copy(deep=True) df.dropna(inplace=True) for col in df.columns: df[col] = (df[col] + 1).cumprod() return df def equity2rate(self, df_equity): df = df_equity.copy(deep=True) df = df.pct_change() return df def calc_equity(self, df_equity): df_rates = self.equity2rate(df_equity) return self.calc_rates(df_rates) def calc_rates(self, df_rates): df_equity = self.rate2equity(df_rates) df_rates.dropna(inplace=True) df_equity.dropna(inplace=True) # 累计收益率,年化收益 count = len(df_rates) accu_return = round(df_equity.iloc[-1] - 1, 3) annu_ret = round((accu_return + 1) ** (252 / count) - 1, 3) # 标准差 std = round(df_rates.std() * (252 ** 0.5), 3) # 夏普比 sharpe = round(annu_ret / std, 3) # 最大回撤 mdd = round((df_equity / df_equity.expanding(min_periods=1).max()).min() - 1, 3) ret_2_mdd = round(annu_ret / abs(mdd), 3) ratios = [accu_return, annu_ret, std, sharpe, mdd, ret_2_mdd] # df_ratio存放这里计算结果 df_ratios = pd.concat(ratios, axis=1) # df_ratios.index = list(df_rates.columns) df_ratios.columns = ['累计收益', '年化收益', '波动率', '夏普比', '最大回撤', '卡玛比率'] # 相关系数矩阵 df_corr = round(df_equity.corr(), 2) start_dt = df_rates.index[0] end_dt = df_rates.index[-1] if isinstance(start_dt, str): start_year = int(start_dt[:4]) end_year = int(end_dt[:4]) df_equity['trade_date'] = df_equity.index df_equity.index = df_equity['trade_date'].apply(lambda x: datetime.strptime(x, '%Y%m%d')) del df_equity['trade_date'] else: start_year = start_dt.year end_year = end_dt.year ''' years = [] for year in range(start_year, end_year + 1): sub_df = df_equity[str(year)] if len(sub_df) <= 3: continue year_se = round(sub_df.iloc[-1] / sub_df.iloc[0] - 1, 3) year_se.name = str(year) years.append(year_se) if len(years): df_years = pd.concat(years, axis=1) else: df_years = None ''' return df_ratios, df_corr# df_years
原创文章第271篇,专注“个人成长与财富自由、世界运作的逻辑与投资“。
日拱一卒,功不唐捐。
我们的目标是星辰大海,围绕投资理财的话题,是一辈子的事情,不着急。
昨天群里星球的同学分享了一个策略——10年12倍,我看了一下,使用我们的框架应该几行代码就可以搞定。
这是一个围绕大类资产轮动的简单策略。使用黄金、美股、A股进行动量轮动。黄金、纳指、创业板和沪深300代表了不同类型、风格和市场的资产,它们之间具有一定的互补性。
我们先设定一个基准: 大类资产的风险平价,季度再平衡:
年化11.1%,最大回撤17.6%。收益率与标普500差不多,但回撤小得多,这就是投资组合,风险平价的价值所有。
from engine.env import Env from engine.algo.algo_weights import * from engine.algo.algos import * etfs = [ '510300.SH', # 沪深300ETF '159915.SZ', # 创业板 '518880.SH', # 黄金ETF '513100.SH', # 纳指ETF ] from engine.datafeed.dataloader import Hdf5Dataloader loader = Hdf5Dataloader(etfs, start_date="20100101") df = loader.load() bench_loader = Hdf5Dataloader(['000300.SH', 'SPX'], start_date='20100101') e = Env(df, benchmarks=bench_loader.load()) e.set_algos([ RunQuarterly(), SelectAll(), WeightRP() ]) e.backtest_loop() e.show_results()
然后我们上今天的策略——动量轮动:
年化26.7%,最大回撤24.9%,是个不错的策略!
代码在如下位置,已经在星球更新:知识星球与开源项目:万物之中,希望至美
from engine.datafeed.dataloader import Hdf5Dataloader from engine.env import Env from engine.algo import * start_date = '20100101' etfs = [ '510300.SH', # 沪深300ETF '159915.SZ', # 创业板 '518880.SH', # 黄金ETF '513100.SH', # 纳指ETF ] loader = Hdf5Dataloader(etfs, start_date=start_date) fields = ['roc(close,20)', 'std(volume,20)', 'bias(close,20)', 'roc(close,5)', 'std(volume,5)', 'bias(close,5)', 'rank(roc_20)'] names = ['roc_20', 'std_20', 'bias_20', 'roc_5', 'std_5', 'bias_5', 'rank'] df = loader.load(fields=fields, names=names) bench_loader = Hdf5Dataloader(['000300.SH','SPX'], start_date=start_date) e = Env(name='roc_20_index', df=df, benchmarks=bench_loader.load()) e.set_algos([ RunDays(2), # SelectAll(), #SelectBySignal(buy_rules=[], sell_rules=['ind(roc_20)<-0']), SelectTopK(drop_top_n=0, K=1, order_by='rank'), WeightEqually() ]) e.backtest_loop() e.show_results()
实践再一次证明,择时从来并不容易,而找到合适的标的池子,进行轮动是可行的。
我们现在有两个策略,今天这个虽然简单,我打算实盘了,就是挑选动量最强的标的持有,简单操作性强。另外是昨天的:
年化27.7%,夏普大于1:加上RSRS大盘择时的行业指数多因子轮动(代码下载)
从29个行业指数ETF取强势的1支轮动。
年化收益41.4%。
以上两个策略进行实盘跟进。
为了方便每日选股操作,我会在GUI系统里提供这样的功能,方便看数据和实盘操作。
近期策略:
发布者:股市刺客,转载请注明出处:https://www.95sca.cn/archives/104062
站内所有文章皆来自网络转载或读者投稿,请勿用于商业用途。如有侵权、不妥之处,请联系站长并出示版权证明以便删除。敬请谅解!