Back to Community
Long/Short Earnings Sentiment Trading Strategy

7/15/2016 Update:

Access to the Estimize dataset will temporarily be shut down starting July 18th, 2016.

We've identified an issue with the manner in which we were processing the Estimize dataset that prevented updates to the data starting June, 2016. All subscribers have been notified and we are taking steps to implement a solution. 

The algorithm here has been updated to use analyst estimates from Zack's Earnings Surprises  

This is similar to a post-earnings announcement drift strategy I’ve published a few months ago that attempts to profit off the difference between reported earnings and earnings estimates based off a white paper by Vinesh Jha. Similar to that algorithm, I use crowdsourced earnings estimates as opposed to the Street’s consensus. The one crucial difference between this strategy and my previous one is that here, I use news sentiment to determine my long/short positions.

The idea is that we only trade on securities with a news sentiment that matches the direction of the earnings surprise. For example, only hold positions in securities with both a positive earnings surprise and a positive news sentiment. This also means that there are two crucial factors influence a trading decision after an earnings announcement and in my opinion, the new method provides a much more clear trading signal than earnings surprises alone.

The inspiration for this algorithm came from Steven Hayes, one of our community members.

Strategy Details:

  • Data set: Earnings calendar by EventVestor, crowdsourced earnings estimates by Estimize, and news sentiment by Accern
  • Weights: The weight for each security is determined by the total number of longs and shorts we have in that current day. So if we have 2 longs and 2 shorts, the weight for each long will be 50% (1.0/number of securities) and the weight for each short will be -50%. This is a rolling rebalance at the beginning of each day according to the number of securities currently held and to order.
  • Capital base: $1,000,000
  • Profit and Loss limits are set to 6%
  • Days held: Positions are currently held for 8 days but are easily changeable by modifying 'context.days_to_hold'
  • Percent threshold: Only surprises between 0% and 6% in absolute magnitude will be considered as a trading signal. These are adjustable using the minimum and maximum threshold variables in context.
  • Earnings dates: All trades are made 1 business day AFTER an earnings announcement regardless of whether it was a Before Market Open or After Market announcement

Notes Since Release

Also as an observation (as of June 21, 2016), I've been live trading
this example strategy for a few weeks now and it seems that in the
past 30~ days, it hasn't made any trades. From what I know it could be
for a few reasons:

  • The trading signal triggers are not being triggered by the earnings
    announcements (perhaps the percent limits are too strict)
  • Estimize's data coverage as compared to someone like Zack's is a
    lot smaller, so the mix of small coverage and the current time of year
    contribute to the lack of triggered trades

Overall, the backtested strategy had relatively few trades and I would
suggest more work is needed to make it robust enough to be holding
positions consistently as opposed to all cash (similar to what Lyth
has worked on).

With analyst earnings surprises from Zacks available soon in pipeline
and estimates to follow, it'll be interesting to see how the two will
compare as the analyst surprises are more robust w/ much wider coverage

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

45 responses

Hi Seong,

I just want to clarify what I am reading.

The following part here:

On Long & Profit

if price >= cost_basis * 1.06 and current_position > 0:
order_target_percent(security, 0)
log.info( str(security) + ' Sold Long for Profit')
del context.stocks_held[security]

On Short & Profit
if price <= cost_basis* 0.94 and current_position < 0:
order_target_percent(security, 0)
log.info( str(security) + ' Sold Short for Profit')
del context.stocks_held[security]

The "cost_basis*.94" is the thing that triggers the 6% profit trigger.... Right? It is this way, not 1.06, because this is a short position.

So if I wanted to trigger every 3% I would just use the cost basis times the .97 for a short and the cost basis * 1.03 for the long.. right?

Thank you Seong for posting this.

Best regards,
Lovis

Yep! If you wanted to you could simplify that like so:

def check_positions_for_loss_or_profit(context, data):  
    # Sell our positions on longs/shorts for profit or loss  
    profit_loss_limit = .03  
    for security in context.portfolio.positions:  
        is_stock_held = context.stocks_held.get(security) >= 0  
        if data.can_trade(security) and is_stock_held and not get_open_orders(security):  
            current_position = context.portfolio.positions[security].amount  
            cost_basis = context.portfolio.positions[security].cost_basis  
            price = data.current(security, 'price')  
            # On Long & Profit  
            if price >= cost_basis * (1 + profit_loss_limit) and current_position > 0:  
                order_target_percent(security, 0)  
                log.info( str(security) + ' Sold Long for Profit')  
                del context.stocks_held[security]  
            # On Short & Profit  
            if price <= cost_basis* (1 - profit_loss_limit)  and current_position < 0:  
                order_target_percent(security, 0)  
                log.info( str(security) + ' Sold Short for Profit')  
                del context.stocks_held[security]  
            # On Long & Loss  
            if price <= cost_basis * (1 - profit_loss_limit) and current_position > 0:  
                order_target_percent(security, 0)  
                log.info( str(security) + ' Sold Long for Loss')  
                del context.stocks_held[security]  
            # On Short & Loss  
            if price >= cost_basis * (1 + profit_loss_limit)  and current_position < 0:  
                order_target_percent(security, 0)  
                log.info( str(security) + ' Sold Short for Loss')  
                del context.stocks_held[security]  

Seong,

Cool! Thanks!
One question, how would I keep a single position rather than compounding a position? What is the code for that?

Best regards,
Lovis

Lovis, I'm not quite sure what you're asking. Is it related to the algorithm above?

Here is an improved version that performs much better out-of-sample.

The days held is set to 4 and the loss limit is set to 3%

Clone Algorithm
2069
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 571f7247c5592a1111f79923
There was a runtime error.

Hi Seong

I took your version and converted it to Long only and saw after adding PvR code that it was shorting and going into neg cash. I implemented Order Tracking, PvR and Queues into this and it no longer holds any neg cash and leverage never goes above 1.

Credit goes to garyha on creating the PvR code, Order Tracking and Queues in other Algos.

PvR - https://www.quantopian.com/posts/pvr-profit-vs-risk

Order Tracking - https://www.quantopian.com/posts/track-orders

Queue Logic from garyha's backtest - https://www.quantopian.com/posts/minimum-variance-w-slash-constraint#56b9683cc3c398a1c200053e

Please let me know what you think and if you can improve further as well. This is looking like a good strategy.

I changed the sell profit and loss limit to 5%, days to hold to 5.

Clone Algorithm
403
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 571f8e6e5572841100f1bd1e
There was a runtime error.

Whoa Steven!

That is pretty tremendous!

Here's a different version that only looks at earnings surprises with Estimize Consensus Estimates that are relevant for the previous quarter.

The factor I use to determine that is here:

class DaysSinceRelease(CustomFactor):  
    # Only getting the previous quarter's estimize surprise  
    window_length = 1  
    inputs = [EarningsCalendar.previous_announcement,  
              ConsensusEstimizeEPS.previous_release_date]  
    def compute(self, today, assets, out,  
                earnings_announcement, estimize_release):  
        days = estimize_release - earnings_announcement  
        out[:] = abs(days.astype('timedelta64[D]').astype(int))  
Clone Algorithm
2069
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 57202621b760b90f7f269956
There was a runtime error.

@Seong - this is a great algo! Good work! However, as I mentioned in my previous posts on some of your other algos, there is a problem with liquidity. Some of the tickers the algo trades would be too illiquid to trade. Is there a way to limit the algo to a certain volume? Aka, 1mm or more?

@Seong - this is a great algo! Good work! However, as I mentioned in my previous posts on some of your other algos, there is a problem with liquidity. Some of the tickers the algo trades would be too illiquid to trade. Is there a way to limit the algo to a certain volume? Aka, 1mm or more?

@Steven - the algo looks pretty impressive! I did run a backtest and a huge bump in returns around 2015/Feb/05 - 2015/Feb/06 got me curious, but I don't quite get what happened there.

Analysing portfolio/transactions around those dates I have discovered that majority of that profit comes from selling 256 shares of HBI on Feb 6th, even though portfolio had only 64 shares the day before.

@Seong does it look like a bug to you?

Clone Algorithm
20
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 571fe0d17bfa450f8105bbaa
There was a runtime error.

Dmitry,

That does look like a pricing bug to me. I've filed the issue internally.

Here's your version of the algorithm (which is different from mine as yours only goes long, includes PvR, diff capital base) without HBI included.

Clone Algorithm
9
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 5720c7250058731157ee2ddf
There was a runtime error.

@Seong - thanks for the update! However, is there a way to keep it long/short without jeopardizing liquidity? Or is that due to the bug?

Daniel, we already have liquidity filters in place. Please adjust that to what you're looking for.

    # Screen out penny stocks and low liquidity securities.  
    dollar_volume = AverageDollarVolume(window_length=20)  
    is_liquid = dollar_volume > 10**7  

I meant to reference @Dmitry in my reply this morning about HBI's pricing issue

@SEong - It's a very interesting strategy, congratulations!

But I think it has a disadvantage:
In the case that just a single company fits the requirements, it will set 100% of the capital in this company.
This increases the volatility and exposure.

Maybe, you can set a minimun percent for each asset:

order_target_percent(security, min(1.0 / len(positive_stocks), 0.5))

And max() for short:
order_target_percent(security, **max**(-1.0 / len(negative_stocks), -0.5))

Thanks,

I cloned this(*) version and the max/min change reduces the drawdown (0.13 to 0.9) and the volatility (0.19 to 0.14) also the returns.

(*) https://www.quantopian.com/posts/long-slash-short-earnings-sentiment-trading-strategy#572028837d121053c8000866

Clone Algorithm
24
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 5721a13876f84e110312eb38
There was a runtime error.

Edit: Thanks for posting Martin, my previous reply was out of place. This is a great algorithm!

Seong,

My previous question is a general question... In the source code above I am wondering what limits order execution. I know you can use the schedule function to limit the number of times it trades... however this doesn't seem to work very effectively.

What I am trying to communicate is how do you tell the computer to enter a position and hold it rather than add to the position if the criteria is met?

In the above example I see "and current_position > 0" for a long profit and "current_position < 0" for a short profit.... does this simple code tell the computer to take a position and hold it until the 3% profit is achieved? Or is there a different code in this algorithm that tells the computer to do this?

What is the code in the above algorithm that says... ? "Take a position and hold it until 3% profit is achieved." The holding part is what I am confused about, I want to understand this.

Best,
Lovis

Lovis,

We enter the positions in order_positions. These positions are held until either a 3% profit or loss is achieved (check_positions_for_loss_or_profit) OR 4 days have passed since we've entered that stock (order_positions).

It seems like you are asking a general python and Quantopian question. Going through our tutorial (https://www.quantopian.com/tutorials/getting-started) will most certainly answer most of the questions you have about how Quantopian algorithms operate.

Thanks!
Seong

My first post here.

I am not sure if I should post because I did nothing except tweaked the take profit and stop loss percent, as well as the weightage. Take profit at 7%, stop loss 4%. Weightage for long at 98%, weightage for short at 25%. A long only strategy (just comment out the line to short) would produce even better return at 108% over the same period, but it'd have periods where it dips into the red region (i.e. dropping below starting capital) during November and December 2012. High weightage on shorts seems to produce poorer result during bull market. But without shorts the performance tanks when there is correction.

I'd say with more tweaking, and addition of other parameters the performance could be pushed further. I like high Sortino ratio for consistency, as well as low 6% max drawdown.

Thanks for providing a framework for newcomers to learn.

Clone Algorithm
97
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 572660907bbc3d0f71620b0f
There was a runtime error.

This is the long-only version, the other parameters should be the same as above.

Clone Algorithm
97
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 5726626487f27e0f7e33d8ee
There was a runtime error.

Great algo Koon,

Here's the out-of-sample results of your algorithm (long/short version) excluding HBI (due to the data issues addressed with Dmitry above).

Clone Algorithm
123
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 57278b9df64f700f9585a7ea
There was a runtime error.

How would it perform over a longer period of years? Like 10 years? I don't have the subscription to run longer test yet, would appreciate if you could post one.

Thank you.

Hi Koon,

I've run this over the timeframe that the dataset is available for (Accern is available starting October 2012 ~ present day with full subscription). I've also excluded HBI from the list of securities.

Beta is a little high so if your goal is to enter this in the contest, it may need some work adjusting the weight on short positions.

Clone Algorithm
123
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 5728c8b75219020f8d725243
There was a runtime error.

Hi,

Thanks Seong Lee.

In make_pipeline, I tried to add the below line
b_profitable = morningstar.asset_classification.growth_grade == "A"

The compiler returned:
NotPipelineCompatible: 0079 asset_classification.profitability_grade is not currently available in the Pipeline API

How do I use get_fundamentals() alongside pipeline? get_fundamentals() has to be used inside before_trading_start. Below is the before_trading_start() in the code you provided.

def before_trading_start(context, data):
results = pipeline_output('estimize')
results = results[results['pe'] == 1]
assets_in_universe = results.index
context.positive_surprise = assets_in_universe[results.longs]
context.negative_surprise = assets_in_universe[results.shorts]

Could you provide an example on how to use the get_fundamental() to create a filter in before_trading_start()?

Hi Koon,

We're actively working on a feature that will allow you to use profitability grade (and other string based fundamental data points) in pipeline. Keep your eyes on the forums for an announcement.

Thanks
Josh

Disclaimer

The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by Quantopian. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. No information contained herein should be regarded as a suggestion to engage in or refrain from any investment-related course of action as none of Quantopian nor any of its affiliates is undertaking to provide investment advice, act as an adviser to any plan or entity subject to the Employee Retirement Income Security Act of 1974, as amended, individual retirement account or individual retirement annuity, or give advice in a fiduciary capacity with respect to the materials presented herein. If you are an individual retirement or other investor, contact your financial advisor or other fiduciary unrelated to Quantopian about whether any given investment idea, strategy, product or service described herein may be appropriate for your circumstances. All investments involve risk, including loss of principal. Quantopian makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances.

I am trying to trade this Algo via Paper trade and it has not traded for the last week. When back testing I see trades however. I am subscripted to the datasets. Any help would be appreciated.

Hi Dennis, here is a backtest during that same time period and it appears that none of the earnings announcements met the trade criteria:

2016-05-17 before_trading_start:140 INFO                       longs  pe shorts  
Equity(110 [ACXM])    False   1  False  
Equity(3496 [HD])     False   1  False  
Equity(7457 [TJX])    False   1  False  
Equity(8229 [WMT])    False   1  False  
Equity(23904 [RRGB])  False   1  False  
Equity(24789 [PLCE])  False   1  False  
2016-05-18 before_trading_start:140 INFO                       longs  pe shorts  
Equity(122 [ADI])     False   1  False  
Equity(1900 [CSCO])   False   1  False  
Equity(2876 [FLO])    False   1  False  
Equity(3668 [HRL])    False   1  False  
Equity(4521 [LOW])    False   1  False  
Equity(6018 [PLAB])   False   1  False  
Equity(6994 [SNPS])   False   1  False  
Equity(7061 [SPLS])   False   1  False  
Equity(7173 [STE])    False   1  False  
Equity(11086 [AEO])   False   1  False  
Equity(11120 [EXP])   False   1  False  
Equity(16820 [TTWO])  False   1  False  
Equity(21090 [TGT])   False   1  False  
Equity(26401 [CRM])   False   1  False  
Equity(27251 [CTRN])  False   1  False  
Equity(40420 [BAH])   False   1  False  
Equity(42738 [RXN])   False   1  False  
Equity(47980 [BOOT])  False   1  False  
2016-05-19 before_trading_start:140 INFO                       longs  pe shorts  
Equity(337 [AMAT])    False   1  False  
Equity(1078 [BRC])    False   1  False  
Equity(3321 [GPS])    False   1  False  
Equity(4794 [MENT])   False   1  False  
Equity(4945 [MNRO])   False   1  False  
Equity(6311 [QSII])   False   1  False  
Equity(6546 [ROST])   False   1  False  
Equity(6969 [SMRT])   False   1  False  
Equity(7623 [TTC])    False   1  False  
Equity(8229 [WMT])    False   1  False  
Equity(8733 [SCVL])   False   1  False  
Equity(13289 [TK])    False   1  False  
Equity(20061 [BRCD])  False   1  False  
Equity(20269 [PERY])  False   1  False  
Equity(22889 [EGHT])  False   1  False  
Equity(23175 [AAP])   False   1  False  
Equity(23395 [SSI])   False   1  False  
Equity(24070 [DKS])   False   1  False  
Equity(26542 [ELOS])  False   1  False  
Equity(27224 [TGP])   False   1  False  
Equity(33041 [TOO])   False   1  False  
Equity(34277 [HGG])   False   1  False  
2016-05-22 before_trading_start:140 INFO                       longs  pe shorts  
Equity(915 [BKE])     False   1  False  
Equity(1795 [CPB])    False   1  False  
Equity(8383 [FL])     False   1  False  
Equity(15815 [HIBB])  False   1  False  
2016-05-23 before_trading_start:140 INFO                      longs  pe shorts  
Equity(5253 [NDSN])  False   1  False  
2016-05-24 before_trading_start:140 INFO                       longs  pe shorts  
Equity(693 [AZO])     False   1  False  
Equity(1898 [CSC])    False   1  False  
Equity(2385 [DY])     False   1  False  
Equity(7530 [TOL])    False   1  False  
Equity(7895 [VAL])    False   1  False  
Equity(8655 [INTU])   False   1  False  
Equity(16307 [VSAT])  False   1  False  
Equity(23873 [KIRK])  False   1  False  
Equity(27409 [DSW])   False   1  False  
Equity(46002 [NMBL])  False   1  False  
Equity(46777 [SPWH])  False   1  False  
Equity(46876 [TOUR])  False   1  False  
Equity(49506 [HPE])   False   1  False  
Clone Algorithm
2
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 5746fdb8c36abd0f94f925a2
There was a runtime error.

Hey Guys (this is my first post in the forums!),
So I put more work into this than I care to admit, but I've corrected a few issues here:
-The issue of the algorithm entering short positions when you've only weighted for long that Steven Hayes identified
-Fixed how surprise was calculated for negative earnings as it was providing incorrect information which caused shorts to enter incorrect positions
-Fixed an issue where it was investing too deeply into securities that it couldn't easily liquidate out of when portfolios got too large
-Optimized the days held and weightings

I think investing into each valid position equally is not the best idea in the end, I'm currently toying with the idea of adding a new signal into the pipeline to sort the strength of each position and weight our entries amounts by that signal. Hopefully someone else can build off this.

Clone Algorithm
181
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 5755e2a1a1b5870f83203ec6
There was a runtime error.

Quick Update to previous algorithm, it actually needs even further reduction in investment with large portfolios so I pegged it down to a flat 1% (from 1.25%) of the mean trading volume over the past 30 days.

I also added a couple lines to invest into SPY when not investing into any other long positions. Since earnings reports all come out generally around the same time and there's a lot of downtime for the algorithm, why not place the money somewhere more productive? This could be elaborated on.

Clone Algorithm
181
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 57570503ccfbc80f84573664
There was a runtime error.

Lyth,

Here's the same algorithm, but without the inclusion of HBI into your universe as there have been some data issues with that security.

Clone Algorithm
18
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 57598b199fb63b0f858d4a12
There was a runtime error.

Hi Koon,

I do appreciate the request. In order to run that backtest you're able to subscribe to the premium sets during that time period. Or you may try and collaborate with other folks on this thread.

Seong

Hi Seong,

Alright, thanks.

Thanks Seong, I actually didn't connect the HBI discussion to that line in code and must have taken it out because I didn't understand it. I've placed it back in. Here's a new algorithm with the following changes

-This algorithm now takes advantage of Accerns impact score
-Stocks with low impact score (lower than 20) are filtered out
-Weights are now determined by impact store
-Also I lowered the amount of downtime investment from 100% to 95% to match the long equity investment.

At this point I'm happy with where the algorithm is at so now I think it might be best to focus on the what the algorithm does when it's not actively trading the strategy. Currently it puts it all in SPY but this seems like a good opportunity to insert a different trading strategy!

Clone Algorithm
181
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 5759d03536d88b0f8b285c84
There was a runtime error.

Nice work Lyth!

That may be a helpful way to take your research as it seems that for the past few days very few earnings announcements have met the filter criteria.

Quoting John Harper on this thread: https://www.quantopian.com/posts/news-and-blog-sentiment-pipeline-factors-with-accern#5759ec3b700321e3df000a47

http://papers.ssrn.com/sol3/papers.cfm?abstract_id=2792559#%23

Abstract:

This paper uses a dataset of more than 900,000 news stories to test whether news can predict stock returns. We measure sentiment with a proprietary Thomson-Reuters neural network. We find that daily news predicts stock returns for only 1 to 2 days, confirming previous research. Weekly news, however, predicts stock returns for one quarter. Positive news stories increase stock returns quickly, but negative stories have a long delayed reaction. Much of the delayed response to news occurs around the subsequent earnings announcement.  

Hi Seong,
Is there a way to act on Earnings Reports the next market open after the information is available and not the market day after?
Setting pe to zero or adding an ne (for next earnings) and setting it to zero seems to not return any results in the algorithm.

Lyth, that's a great question and I hope to do my best in answering it.

I generally wouldn't advice on trying to act on Earnings Reports on the market open because of one main reason:

  • At the moment, you do not have an accurate way of knowing whether or not an earnings announcement was before or after market open. In the case that it was after market open and your logic is testing for nextearningsannouncement == 0, you'll essentially miss all earnings reports that fall after 4:00PM.
  • Because pipeline provides data on a daily basis, Estimize's consensus estimates and Accern's alphaone are both getting yesterday's data, today. This is why your algorithm is not making any trades, because the data present on t==0 aren't meeting the necessary conditions for the algorithm to trade.

Hope that helps and I'm happy to help answer any questions

Seong

Also as an observation, I've been live trading this example strategy for a few weeks now and it seems that in the past 30~ days, it hasn't made any trades. From what I know it could be for a few reasons:

  • The trading signal triggers are not being triggered by the earnings announcements (perhaps the percent limits are too strict)
  • Estimize's data coverage as compared to someone like Zack's is a lot smaller, so the mix of small coverage and the current time of year contribute to the lack of triggered trades

Overall, the backtested strategy had relatively few trades and I would suggest more work is needed to make it robust enough to be holding positions consistently as opposed to all cash (similar to what Lyth has worked on).

With analyst earnings surprises from Zacks available soon in pipeline and estimates to follow, it'll be interesting to see how the two will compare.

Has anyone modified the strategy to use Zacks yet?

We've recently found an issue with the Estimize Consensus Estimates dataset in how updates are being made. While we're still investigating the problem, what we know so far is that updates to the dataset are not properly being delivered to algorithms. This appears to have been happening since the beginning of June, 2016.

To prevent algorithms from using this dataset until we've addressed and implemented the solution, we're shutting down access to the Estimize Consensus Estimate starting Monday, July 18th.

This algorithm has instead been modified to use analyst earnings surprises from Zacks

Clone Algorithm
652
Loading...
Backtest from to with initial capital
Total Returns
--
Alpha
--
Beta
--
Sharpe
--
Sortino
--
Max Drawdown
--
Benchmark Returns
--
Volatility
--
Returns 1 Month 3 Month 6 Month 12 Month
Alpha 1 Month 3 Month 6 Month 12 Month
Beta 1 Month 3 Month 6 Month 12 Month
Sharpe 1 Month 3 Month 6 Month 12 Month
Sortino 1 Month 3 Month 6 Month 12 Month
Volatility 1 Month 3 Month 6 Month 12 Month
Max Drawdown 1 Month 3 Month 6 Month 12 Month
# Backtest ID: 5788ee13617d8f11f85202d8
There was a runtime error.

Access to the Estimize dataset will temporarily be shut down starting today.

We've identified an issue with the Estimize dataset that prevented updates to the data starting June, 2016. All subscribers have been notified and we are taking steps to implement a solution.

For an alternative version using Wall Street Consensus Estimates, please view this thread: https://www.quantopian.com/posts/updated-long-slash-short-earnings-sentiment-trading-strategy-with-the-streets-consesus

Hi, Seong
Thanks for your strategy!
Could you recommend me some articles about how you get the surprise limitation ,the profit limitation and sentiment limitation?

Karen

Hi Seong,

I do not quite understand why you set a maximum for surprise magnitude. After all, won't greater surprise generate greater momentum? Say in Case 1 the actual beats the estimate by 10% and in Case 2 the actual beats the estimate by 5%. I would expect more upward price movement in Case 1 than in Case 2. Why set a maximum to NOT trade Case 2? What is the rationale for setting the surprise range? Thanks!

Neo