V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
thinkingmind
V2EX  ›  推广

[神奇公式] 如何在 Ricequant 上实现策略( Python) - 1 从别人的经验和思路中实现

  •  
  •   thinkingmind · 2016-04-05 14:53:52 +08:00 · 4528 次点击
    这是一个创建于 3147 天前的主题,其中的信息可能已经有所发展或是发生改变。

    原帖、更多讨论及代码: https://www.ricequant.com/community/topic/815

    我们提供了较为丰富的入门教学材料和视频,可能您还是会有疑问如何开始呢?我们就从一个简单的例子开始来看看吧,是非常流行的神奇公式

    我最开始是在网上浏览看到这个公式的,那么其作者是格林布拉特:

    乔尔•格林布拉特简介 Gotham 资本公司的创始人和合伙经理人,自 1985 年这一私人投资公司成立以来,它的年均回报率达到了 40%。他不仅是哥伦比亚大学商学院的客座教授,一家《财富》 500 强公司的前董事长,价值投资者俱乐部网站( ValueInvestorsClub.com )的合作发起人,还是《你能成为股市天才》一书的作者。格林布拉特拥有理学学士学位,并从沃顿学院获得工商管理硕士学位。

    [《证券市场周刊》记者王存迎] 乔尔·格林布拉特的投资理念是要找到物美价廉的公司,特别是在市场出现特殊情况的背景下低价买入好业务。    “便宜价格买好业务是神奇公式的核心理念。神奇公式能够帮助不懂估值的投资人战胜大盘,而对于精通估值的投资人,神奇公式则能给他们提供一个起点,他们的估值能力还能给神奇公式加分。”他如此评价他自己发明的神奇公式,认为神奇公式是戈坦资本投资流程的简化版。    在《股市稳赢》一书中,格林布拉特详细介绍了神奇公式的应用方法。其具体操作流程可以简化成两部分:一是寻找好的业务;二是寻找便宜的股票。好的业务是指有形资本回报率高的公司;便宜的股票则是指息税前盈余 /企业价值( EBIT/ EV )高的股票。

    利用神奇公式,在美国的历史回溯检验数据显示, 1988 年至 2004 年这 17 年间,该策略的年复合回报率为 30.8%,而同期标准普尔 500 指数的年复合回报率仅为 12.4%。

    接着我们开始找这个公式的真正原版是什么吧!经过一系列的 google 之后我还是比较相信 wikipedia : https://en.wikipedia.org/wiki/Magic_formula_investing

    Methodology[edit]

    Greenblatt suggests purchasing 30 "good companies": cheap stocks with a high earnings yield and a high return on capital. He touts the success of his magic formula in his book 'The Little Book that Beats the Market ', Joel Greenblatt ISBN 0-471-73306-7, citing that it does in fact beat the S&P 500 96% of the time, and has averaged a 17-year annual return of 30.8%[1]

    Formula[edit]

    • Establish a minimum market capitalization (usually greater than $50 million).
    • Exclude utility and financial stocks.
    • Exclude foreign companies (American Depositary Receipts).
    • Determine company's earnings yield = EBIT / enterprise value.
    • Determine company's return on capital = EBIT / (net fixed assets + working capital).
    • Rank all companies above chosen market capitalization by highest earnings yield and highest return on capital (ranked as percentages).
    • Invest in 20 – 30 highest ranked companies, accumulating 2 – 3 positions per month over a 12-month period.
    • Re-balance portfolio once per year, selling losers one week before the year-mark and winners one week after the year mark.
    • Continue over a long-term (5 – 10+ year) period.

    翻译一下就是:

    1. 排除掉公共事业和金融板块的股票。(为什么呢?这个可能需要从作者的那本书名很俗的书中寻找)
    2. 排除掉境外的公司( A 股基本没有)
    3. 选取公司的息税前盈余 /企业价值高的 = EBIT / Enterprise Value 《---- 便宜的股票是指税前盈余 /企业价值( EBIT/EV )高的股票。
    4. 选取公司的有形资本回报率( return on capital )= EBIT / (Net Fixed Assets + Working Capital) <--- 好的业务是指有形资本回报率高的公司
    5. 从所有市面上的股票中选取 3 和 4 最高的公司的股票
    6. 投资 20-30 个排名最高的股票,然后每个月持续加入 2-3 个持仓直到超过 12 个月
    7. 每年进行重新调整投资组合,年前剔除掉当年投资比较失败的,年后剔除掉当年投资比较成功的
    8. 长期继续以上的操作( 5-10 年+)

    在整个公式分析中如何一步一步在 Ricequant 上实现呢?我们先从比较简单的版本做起,剔除掉 6-8 的复杂操作,假设每个月调仓投资 20-30 个符合 3-4 点的股票。

    咱们来一个一个拆开分析,符合计算机的divide and conquer - 各个击破的思想吧!

    1. 排除掉公共事业和金融板块的股票。

    这个需要使用 Ricequant 提供的板块功能: https://www.ricequant.com/api/python/chn#other-methods-sector

    context.utlility_and_fin_stocks = sector('utilities') + sector('financials')
    logger.info(context.utlility_and_fin_stocks)
    

    我们使用sector拿到utilitiesfinancials两个板块的股票,然后返回的是两个array相加得到一个包含两个板块的 array ,我也会习惯打印一句logger.info(xx)来把我们拿到的这俩板块的股票列表显示出来。


    2. 选取公司的息税前盈余 /企业价值高的 = EBIT / Enterprise Value 《---- 便宜的股票是指税前盈余 /企业价值( EBIT/EV )高的股票。

    比较赞的是 Ricequant 提供的财务数据表格查询是非常齐全和清洗的,也包含了专业的英文命名: https://www.ricequant.com/fundamentals

    我们需要首先寻找到 EBIT 和 Enterprise value ( EV )在 Ricequant 的命名: Screen Shot 2016-04-03 at 4.59.39 PM.png

    比较有意思的是我们直接找到了 EV/EBIT ,但是我们需要寻找的是 EBIT/EV 的最高的几名,因此从EV/EBIT这个指标我们只需要的排序是从低到高的前几名即可,那么转化为查询代码(对查询财务数据不熟悉,可以看我们的财务数据教程视频):

    我们首先要提前考虑的是我们需要查询两个指标:EBIT/EV资本回报率( return on capital ), 分别会拿到两组的公司列表,然后找两个列表中的共同股票就是最后的所得,由于财务数据的查询量会比较大,我们做一个 200 的查询限制,先查EV/EBIT的从低到高的排序:

    context.limit = 200
    ebit_div_ev_df = get_fundamentals(
            query(
                fundamentals.eod_derivative_indicator.ev_to_ebit
            ).order_by(
                fundamentals.eod_derivative_indicator.ev_to_ebit.asc()
            ).limit(
                context.limit
            )
        )
    

    PS:

    1. 这里有个命名的建议是,所有的dataframe数据类型我都建议您使用_df作为结尾,这样看到这个变量名,您就可以知道他是dataframe的数据类型了。
    2. fundamentals.eod_derivative_indicator.ev_to_ebit 就是我们在财务数据字典中查到的指标名。
    3. order_by(fundamentals.eod_derivative_indicator.ev_to_ebit.asc())是对该指标进行一个从小到大的排序,然后选取前context.limit个 - 即前 200 个

    3. 接着我们开始查询资本回报率( return on capital ),幸运的是我们强大的财务数据字典依然有:

    Screen Shot 2016-04-03 at 5.28.06 PM.png

    那么我们开始构建资本回报率的财务数据查询:

    return_on_cap_df = get_fundamentals(
            query(
                fundamentals.financial_indicator.return_on_invested_capital
            ).order_by(
                fundamentals.financial_indicator.return_on_invested_capital.desc()
            ).limit(
                context.limit
            )
        )
    

    那么此时我们拿到了两个dataframe分别是ebit_div_ev_dfreturn_on_cap_df,但是我们要拿的是在这两个df中都存在的股票,因此做以下的代码操作:

    df_stocks = [stock for stock in ebit_div_ev_df if stock in return_on_cap_df]
    

    但是我们仍旧需要去除掉属于公共事业和金融板块的股票代码:

    for stock in df_stocks:
        if stock in context.utlility_and_fin_stocks:
            df_stocks.remove(stock)
    

    我们只需要前 30 个即可:

    context.total_amount = 30
    context.stocks = df_stocks[0:context.total_amount]
    logger.info("选择好的神奇公式股票列表为:" + str(context.stocks))
    

    那么context.stocks就是最终我们需要的符合神奇公式的股票列表啦!

    原帖、更多讨论及代码: https://www.ricequant.com/community/topic/815

    4 条回复    2016-04-06 10:53:15 +08:00
    0x5010
        1
    0x5010  
       2016-04-05 15:48:41 +08:00
    很有想法.
    nilom
        2
    nilom  
       2016-04-05 16:17:22 +08:00
    先学习再收藏
    l6751902
        3
    l6751902  
       2016-04-06 09:21:50 +08:00
    最近怎么有种量化开始向“一般人”扩展的趋势?韭菜少了,机构开始想从码农这头扩展羊群么?
    thinkingmind
        4
    thinkingmind  
    OP
       2016-04-06 10:53:15 +08:00
    @l6751902 很多量化交易者出生就是码农,尤其是高频交易一块,当然在国内高频做不动了。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2645 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 11:27 · PVG 19:27 · LAX 03:27 · JFK 06:27
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.