Hi there,
I am trying to use the Universe feature to apply some filters on the securities to trade.
However when I test it out with a very simple filter, I already get some securities that should not go through.
AddUniverse(coarse => {
return (from c in coarse
where c.Price < 30
orderby c.DollarVolume descending
select c.Symbol).Take(10);
});
Then in the event "OnSecuritiesChanged", I am performing a MarketOnOpenOrder on the Universe filtered Securities.
foreach (Security security in changes.AddedSecurities)
{
MarketOnOpenOrder(security.Symbol, 100);
}
However in the traded securities I can see the following:
2011-05-03 00:00:00 C $43.55112507 MarketOnOpen Long Filled
2011-05-03 00:00:00 BAC $11.64248332 MarketOnOpen Long Filled
2011-05-01 00:00:00 SPY $119.889125334 MarketOnOpen Long Filled
Why did the universe catch those Equities for which the price is higher than 30?
Is it a bug or did I miss something?
LukeI
Edit: sorry for Python code, that's all I have
I had the same problem, but found the solution. I might be wrong on some of this stuff but this is how I understand it:
Basically, the universe uses raw (non-adjusted) prices that don't take into account splits and some other factors. This isn't really an issue on recent backtests or live trading but it's a signifigant issue when you are looking far into the past. The solution to this is to add an additional price filter to your securities, outside of the universe function, based on history data which is adjusted.
def OnData(self, data):
# if we have no changes, do nothing
if not self.changes == SecurityChanges.None:
# liquidate removed securities
for security in self.changes.RemovedSecurities:
if security in self.stocks_long:
self.stocks_long.remove(security)
#Add securities to long list that meet our price criteria
for security in self.changes.AddedSecurities:
if not security in self.stocks_long:
history = self.History(security.Symbol, 1, Resolution.Daily)
if history.empty: continue
if (len(self.stocks_long) < 100) and (history['close'][0] <= self.PriceLimit):
self.stocks_long.append(security)
else:
pass
#self.RemoveSecurity(security.Symbol)
self.changes = SecurityChanges.None
# this event fires whenever we have changes to our universe
def OnSecuritiesChanged(self, changes):
self.changes = changes
Sylvain Zenatti
Thanks! Great answer!
Could it be for the same reason explaining why I don't get the exact same results on historical data when I compare the prices between the backtest (few years in the past) with "tradingview"?
Dan Whitnable
A word of caution about using 'History' to check for absolute values like price.
Lukel is correct that (as of this posting) the prices and volumes returned are adjusted values. However, they are adjusted with splits and dividends all the way forward in time to the current date.
Take stock XYZ that sold for $11 on 6/1/2015. That is the actual price one could buy it for on that date. (this is referred to as the 'raw' value in QC). Now assume there is a 2:1 stock split on 9/1/2016.
The course universe selection uses actual (ie 'raw') data. It will correctly filter any absolute values like 'price > 10'. However, the 'History' method returns adjusted values and includes splits that haven't even happened yet. It will include the future 2:1 split and return a price of $5.50 for stock XYZ on 6/1/2015 (which is clearly wrong). Filtering on these 'History' values like 'price > 10' would incorrectly filter out our XYZ stock.
I believe this 'bug' in the 'History' method is being addressed (
) but as of this posting, the only thing that History data should probably be used for is relative comparisons like percent change or simple directional (higher or lower) checks.
Sylvain Zenatti
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 QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect 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. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
To unlock posting to the community forums please complete at least 30% of Boot Camp.
You can continue your Boot Camp training progress from the terminal. We hope to see you in the community soon!