Quantopian's community platform is shutting down. Please read this post for more information and download your code.
Back to Community
Recording Turnover

Is there a recommended way of recording turnover ourselves? Can this be done within the scope of the contest rules? I know TargetWeights can be used to mimic order_target_percent- I would like to go a step further and be able to retrieve order object information in order to infer turnover rates.

When I print the order_optimal_portfolio object I get something like

['4c41d4610c31423e9fdbddff72e9b3d8', 'a18fcef941d148b5b0a803490a4de8ed', 'f02dd9d8c3af43cda119937c7d8ecbc7', '73038b27fc8745eea710fab34343cfc3', '1fc9fdc4499c4d50912a7493d9b10ed3', '4741e8250f9f431591938df8a3e1b6cd', '12ba019501a146598001ef1c59221390', '0edd19a4fdf8481f94589e012804d763', '12974607cb4d4549ae5de5a839cbd2b7', '2f817d50638b436fa6e7c0b27943c21b', 'fa804d61ea7d4df49f60e1d3343f8ff3', 'cf5d7771e5fe4dbb98fa310355ca622e', '4192ec05b4e743a5b3fcd9fc384e510d', '18f956e4e6524d2bbc503cd5ef710493', '0493477727bb489382d83e0b07a78bc3', '6b4e4d08167b433c9e6b44fa6fb1ae82', 'aee68ebe8e114d7798671256fbe96420', '309bff4cadc1430287a6c4b088ddf650', 'f7f02bd2766b4385a6efab5bd7ac1a39', '94169a0f70fc46048ebaa66291fd5e59', 'f77785782a5a4d2bbd75a9d9adbc9a7e', '51c1c767e72e461c873189fc1faf1689', '4ed95dfba6404075bc00288af0bc5def', 'e10d06850baf4a9983fafb84f8c540ca', 'bdb4d50590d942d99b9bd1954c8c01ec', 'a6e7427139314ff680fe4b1050cf1f5c', 'f74a27e2d38a4028aa3870dffce497c3', '596106df6aaa4cb0b674e8f90d4f1fa7', 'cae53852d4344c...

A solution for the above would also help me answer this question: https://www.quantopian.com/posts/what-is-the-turnover

Thanks!

3 responses

Turnover on the Quantopian platform is defined as

capital traded  /  portfolio_value

The capital that will be traded by a set of orders (eg by using order_optimal_portfolio) can be thought of as the difference between the current portfolio holdings and the target portfolio holdings. Dividing those values by portfolio_value one get's the portfolio weights. So, another way to get turnover is

sum of abs(current portfolio weights - target portfolio weights)

One doesn't need to fetch order object information to get turnover. Simply get the current portfolio weights and subtract the optimized portfolio weights. This will give the 'change in portfolio weights'. Take the absolute values of these weights and sum them up. That will be the daily turnover. Something like this

# First get the optimized calculated weights but not actually order  
opt_weights = opt.calculate_optimal_portfolio(objective=target_weights, constraints=constraints)

# Get the current portfolio weights.  
# Turnover is the difference between the current weights and the optimized weights  
current_weights = context.portfolio.current_portfolio_weights  
difference = opt_weights.subtract(current_weights, fill_value=0.0)  
turnover = difference.abs().sum()  

Note, one can't simply subtract the current and optimized weights like this

difference = opt_weights - current_weights

If a security is in one weighting and not the other, the result will be nan. Not what we want. The pandas method subtract to the rescue. This method allows for 'filling' any values in one series and not the other with a value (eg 0). See https://pandas.pydata.org/pandas-docs/version/0.18/generated/pandas.Series.subtract.html.

Also note this is the daily turnover. The contest constraint is for the mean daily turnover to be between 5%-65% measured over a 63-trading-day rolling window. To get the 63 day mean value, one would need to store this daily value then find the mean of the last 63 values.

The attached example simply logs the turnover. However, one could conceivably modify the optimized weights or do other logic if turnover is too high.

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.

Thanks for your in-depth response/example algo, Dan. That cleared up a lot of my confusion.

Just want to confirm one nuance - are you saying that Quantopian evaluates turnover based on orders actually filled or merely placed by order_optimal_portfolio? I had assumed the former but I am gathering the latter is the actual methodology. Or is it technically the former, but not a big enough difference in practice to warrant providing infrastructure for an orders-style object?

I only occasionally see warnings about unfilled orders - but I thought it might be of theoretical interest to have access to fill information, regardless. I guess I could just save a snapshot of context.portfolio.positions at close and extrapolate unfilled orders from that? (Sorry if I'm answering my own question...though on second thought this might not work if trades are executed end of day...or maybe it would...I'll look into this myself :))

P.S. I know the QTradableStocksUS includes filters for liquidity, but no filter is perfect. In fact, I would prefer to have a universe that included illiquid assets precisely to implement a strategy based on actual vs projected turnover. (I guess the only thing stopping me from straying from ol' QTrad are contest rules; maybe I'll dig a little deeper, wean myself off of backtests and do some actual research.) But there's gotta be somebody out there with a similar vision who's ventured into this territory already...

Cheers and happy holidays

@Christopher Sorry for not being more clear. You asked "Just want to confirm one nuance - are you saying that Quantopian evaluates turnover based on orders actually filled or merely placed by order_optimal_portfolio? " Quantopian bases turnover on the actual executed and filled trades.

The approach above was intended as a way to estimate the impact of placing orders using the order_optimal_portfolio method. By knowing this estimate, one could modify the orders to potentially stay within the turnover limits. This is a good estimate (typically most orders fill) but isn't the actual turnover. If one is only trading once per day, the actual turnover can be found using a similar method.

# Turnover is the difference between the current weights and the previous weights  
current_weights = context.portfolio.current_portfolio_weights  
difference = context.previous_weights.subtract(current_weights, fill_value=0.0)  
turnover = difference.abs().sum() 

# Save the current days portfolio weights to compare tomorrow  
context.previous_weights = current_weights  

The portfolio weights will reflect the actual traded securities and therefore the actual turnover. However, if one trades more than once during the day, the intra-day trades may not be captured using this approach and actual turnover could be higher. Unfortunately, there isn't a simple way to find the actual dollars traded if trading intra-day. While one can save the order objects, the orders only contain the quantity of shares filled and not the actual fill price. The price is needed to calculate turnover.

Hope that clears up my initial response?