石园理财

您现在的位置是:首页 > 经验分享 > 正文

经验分享

量化投资之路2:资金流向2-如何通过资金流选股(资金流选股模型)

sddy0082023-03-12经验分享110

阅读下面文章前,请保证zvt的环境已经准备好。

源码:

https://github.com/zvtvz/zvt https://gitee.com/null_071_4607/zvt

文档:

https://zvtvz.github.io/zvt/ http://zvt.foolcage.com

1. 一段时间资金的动向

如果今天资金流入,你就买,明天资金流出,你就卖,你的成功率不会很高;我们需要关注的是,一段时间资金的动向。

一段时间,就是 窗口(window);而好坏都是对比出来的,所以,我们需要排序。

可以这么选择:最近20天 净流入额 和 流入率 排名前3的板块

这里的参数可以自己调整,这跟自己交易周期的偏好有关,并无绝对好坏之分;但有一点是肯定的,只参与资金关注的板块。

2. 实现自己的factor

zvt里面有三类factor:FilterFactor,ScoreFactor,StateFactor。

我们的算法是:20日流入额和流入率越高,分数就越高,所以,选择ScoreFactor。

class IndexMoneyFlowFactor(ScoreFactor): def __init__(self, the_timestamp: Union[str, pd.Timestamp] = None, start_timestamp: Union[str, pd.Timestamp] = None, end_timestamp: Union[str, pd.Timestamp] = None, columns: List = [IndexMoneyFlow.net_inflows, IndexMoneyFlow.net_inflow_rate, IndexMoneyFlow.net_main_inflows, IndexMoneyFlow.net_main_inflow_rate], filters: List = None, order: object = None, limit: int = None, provider: str = sina, level: Union[str, IntervalLevel] = IntervalLevel.LEVEL_1DAY, category_field: str = entity_id, time_field: str = timestamp, trip_timestamp: bool = True, auto_load: bool = True, keep_all_timestamp: bool = False, fill_method: str = ffill, effective_number: int = 10, scorer: Scorer = RankScorer(ascending=True)) -> None: super().__init__(IndexMoneyFlow, None, index, None, None, the_timestamp, start_timestamp, end_timestamp, columns, filters, order, limit, provider, level, category_field, time_field, trip_timestamp, auto_load, keep_all_timestamp, fill_method, effective_number, scorer) def pre_compute(self): self.depth_df = self.data_df.copy() self.depth_df = self.depth_df.groupby(level=1).rolling(window=20).mean() self.depth_df = self.depth_df.reset_index(level=0, drop=True) self.depth_df = self.depth_df.reset_index() self.depth_df = index_df_with_category_xfield(self.depth_df)

在评分之前首先把所有时间点的值进行window计算:

def pre_compute(self): self.depth_df = self.data_df.copy() self.depth_df = self.depth_df.groupby(level=1).rolling(window=20).mean() self.depth_df = self.depth_df.reset_index(level=0, drop=True) self.depth_df = self.depth_df.reset_index() self.depth_df = index_df_with_category_xfield(self.depth_df)

然后使用Scorer来对其进行评分,即标准化为[0,1]的分数,这里我们直接使用zvt里面已经实现的 RankScorer:

class RankScorer(Scorer): def __init__(self, ascending=True) -> None: self.ascending = ascending def compute(self, input_df) -> pd.DataFrame: result_df = input_df.groupby(level=1).rank(ascending=self.ascending, pct=True) return result_df

groupby(level=1)意思是按时间分组,rank评分规则是 升序 和 百分比,这样我们就得到了一个标准的zvt二维索引DataFrame,level0为标的,level1为时间序列。

3. 选择器

分数有了,我们就可以定义 TargetSelector 来选择标的了。

class IndexSelector(TargetSelector): def __init__(self, entity_ids=None, entity_type=stock, exchanges=[sh, sz], codes=None, the_timestamp=None, start_timestamp=None, end_timestamp=None, long_threshold=0.8, short_threshold=0.2, level=IntervalLevel.LEVEL_1DAY, provider=sina, block_selector=None) -> None: super().__init__(entity_ids, entity_type, exchanges, codes, the_timestamp, start_timestamp, end_timestamp, long_threshold, short_threshold, level, provider, block_selector) def init_factors(self, entity_ids, entity_type, exchanges, codes, the_timestamp, start_timestamp, end_timestamp, level): index_factor = IndexMoneyFlowFactor(start_timestamp=start_timestamp, end_timestamp=end_timestamp, level=level, provider=sina, codes=codes) self.score_factors.append(index_factor)

这里设置long_threshold为0.8,意思就是比80%的其他板块分数要高。

在ipython里面看一下:

In [1]: from examples.factors.composite_selector import * from zvt.api import * In [2]: df = get_blocks(provider=sina, block_category=industry) index_selector = IndexSelector(entity_type=index, exchanges=None, start_timestamp=2019-01-01, end_timestamp=now_pd_timestamp(), codes=df[code].to_list()) index_selector.run()

看一看某天选出的板块:

In [12]: blocks = index_selector.get_targets(timestamp=2019-09-02) In [13]: get_index(entity_ids=blocks,provider=sina) Out[13]: id entity_id timestamp entity_type exchange code name is_delisted category base_point list_date timestamp NaT index_cn_new_jdhy index_cn_new_jdhy None index cn new_jdhy 家电行业 None industry None None NaT index_cn_new_jdly index_cn_new_jdly None index cn new_jdly 酒店旅游 None industry None None NaT index_cn_new_jjhy index_cn_new_jjhy None index cn new_jjhy 家具行业 None industry None None NaT index_cn_new_jrhy index_cn_new_jrhy None index cn new_jrhy 金融行业 None industry None None NaT index_cn_new_jtys index_cn_new_jtys None index cn new_jtys 交通运输 None industry None None NaT index_cn_new_jxhy index_cn_new_jxhy None index cn new_jxhy 机械行业 None industry None None

这里的关键点在于get_targets接收 回测时间 即返回所在时间选取的标的,嗯,没错,是回测时间,TargetSelector放到Trader里面就可以进行回测。

4. 行业包含的个股

选取了行业,那么怎么知道行业包含的个股呢? 使用api get_securities_in_blocks 即可:

In [14]: get_securities_in_blocks(provider=sina,categories=[industry],codes=[new_jdly]) Out[14]: [stock_sh_600054, stock_sh_600138, stock_sh_600258, stock_sh_600358, stock_sh_600555, stock_sh_600593, stock_sh_600640, stock_sh_600706, stock_sh_600749, stock_sh_600754, stock_sh_601007, stock_sh_601888, stock_sh_603099, stock_sh_603199, stock_sh_603869, stock_sz_000007, stock_sz_000069, stock_sz_000428, stock_sz_000430, stock_sz_000524, stock_sz_000610, stock_sz_000613, stock_sz_000721, stock_sz_000802, stock_sz_000888, stock_sz_000978, stock_sz_002033, stock_sz_002059, stock_sz_002159, stock_sz_002186, stock_sz_002306, stock_sz_002558, stock_sz_002707, stock_sz_300144, stock_sz_300178]

5. 多因子选股

板块是选出来了,但我们要的是个股,并且个股本身我们也需要做一些条件的过滤,比如我们只要日线MACD黄白线在0轴上的个股,怎么做呢?

我们直接使用zvt里面实现 BullFactor 即可:

class TechnicalSelector(TargetSelector): def __init__(self, entity_ids=None, entity_type=stock, exchanges=[sh, sz], codes=None, the_timestamp=None, start_timestamp=None, end_timestamp=None, long_threshold=0.8, short_threshold=0.2, level=IntervalLevel.LEVEL_1DAY, provider=joinquant, block_selector=None) -> None: super().__init__(entity_ids, entity_type, exchanges, codes, the_timestamp, start_timestamp, end_timestamp, long_threshold, short_threshold, level, provider, block_selector) def init_factors(self, entity_ids, entity_type, exchanges, codes, the_timestamp, start_timestamp, end_timestamp, level): bull_factor = BullFactor(entity_ids=entity_ids, entity_type=entity_type, exchanges=exchanges, codes=codes, the_timestamp=the_timestamp, start_timestamp=start_timestamp, end_timestamp=end_timestamp, provider=joinquant, level=level) self.add_filter_factor(bull_factor)

个股选择配合板块选择,只需要把之前的index_selector加到个股的selector里面即可:

s = TechnicalSelector(codes=SAMPLE_STOCK_CODES, start_timestamp=2019-01-01, end_timestamp=2019-06-30, block_selector=index_selector) s.run() s.draw()

这里只使用SAMPLE_STOCK_CODES进行测试,实际使用中应该使用全市场进行,并且还要考虑其他因素。

6. 小结

通过这篇文章,我们基本了解了如何使用 ScoreFactor 进行板块选择,并在此基础上结合个股技术指标来进行综合选股。 选出来是选出来了,其历史表现如何呢?我们下一节见。

知乎专栏:

https://zhuanlan.zhihu.com/automoney

github:

https://github.com/zvtvz/automoney

公众号:

发表评论

评论列表

  • 这篇文章还没有收到评论,赶紧来抢沙发吧~