Back to Community
What prices does Q backtester apply on intra day trading?
API

I'm getting very different pricing on my internal controls than on Q's backtester on one of my frequent trading/intraday algos. This is regardless of how I tweak the fee and slippage settings. I've already determined its due to filled pricing differentials, which on frequent trades of 5 or 6 per stock per day, add up to a lot of moolah.

So my understanding is that Q listens and gathers data from IB and send it along every minute. So if a price rises from 100.00 to 100.30 in minute 9:32-9:33 am it will report the OHLC minute bar at 9:33 as 100.00 / 100.30 / 100.00 / 100.30.

1) If I then fire off an order to buy a 9:33:01 with order_target_percent(context.stock,1), when will it get sent to IB ? At 9:33:01:xx or at 9:34?

2) Does Q assume the fill price is the mean price of the next minute bar (9:34) , or the weighted average price or the closing price of the next bar?

If the answer to the first question is "immediate" (9:33:01), the a solution for day trading in order to assure good pricing is to only send
limit orders or stop / limit , to monitor closely whether or not they get filled and to cancel them and resend them as appropriate for the strategy

If the answer is "delayed by one minute", then intraday strategies , imho, become efforts in futility on Q's platform. That would be a shame, but at least I would know to only focus on swing trading strategies.

I appreciate all input.

10 responses

The price are filled at the close price of the next minute bar but you can easily customize the slippage model to fill the price at the open price of next bar. Please see: https://www.quantopian.com/posts/trade-at-the-open-slippage-model

Luca,

Thanks. That explains the huge difference in results. I will get cracking on modifying my code to fill at open

Serge, Luca's answer is correct for the backtester. I'd like to explore a little farther, though, for IB.

In the backtester, an order is placed in bar (n), then it is filled at the close price of bar (n+1). The order fill price and volume is determined by the Quantopian backend, aka Zipline.

However, once you connect to the broker, the behavior changes. When you place an order in bar(n), then that order is sent to IB essentially immediately. The fill price is determined by IB (either the IB paper trading calculation or IB real money).

What that means: in backtesting, you're getting a simulated fill price that is fairly conservative and has no look-ahead bias. When you're connected to the broker, you're generally getting the order in much faster, and getting a price much closer to the market price.

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.

Dan

Thaks for the clarification, which is what I expected.
FYI. There is still a little glitch with the Q backtester, I believe. I used the logic Luca pointed to to make my orders fill at open plus 10% of op/close price, which in my experience of live trading should be pretty close. (The real test will be live (not paper) trading on IB , of course) Now I'm getting executions that seem correct. When I use the recording function to trace my p&l loss, including all transaction fees, I have a period in which I have a modest profit. Yet during that same period the Q backtester shows a loss, and in fact trades continue to execute at bar close prices, not bar open + 10% of bar diff.

In the final model I will test on IB, I will in fact use LIMIT and STOP/LIMIT orders, and add in logic to test for a fill, and rinse/repeat based on those results.

I'm sure there are bugs in the backtester somewhere - all software has them. That said, we're moving through 7 million years of backtesting, and we've had thousands of people scrutinize their backtest results, so the software is reasonably burned in.

If you share a backtest and say where the unexpected behavior is, we can dig into it.

Thanks Dan,

Ok.I'll trace into it more. Before I spent a lot of time doing so, I wanted to make sure it wasn't some small little variable I had to set in the logic to account for minute versus daily data.

I suspect difference might also be in my commission settings, as in my algo I am using actual IB commission schedule, but in my test I set

set_commission(commission.PerShare(cost=0.0075, min_trade_cost=1.00))

On trades every 5 minutes, that can add up VERY QUICKLY.

Once I get to the bottom of this, I'll post my results here for others' benefit.

Thanks

Well, it was not the commission setting, as I changed this to match that used in my profit/loss calculation within my debugger.
But reviewing the log files, I discovered something odd, that I don't understand.

I had been using this to order my shares:
context.order_id=order_target_percent(context.stock, 1)

and this to sell them again

      context.order_id=order_target_percent(context.stock, 0)    

assuming this would make sure I did not get messed up in my buying or selling too few /many shares.

But if you look at the log picture attached, the algo in Q's debugger buys 4913 shares at 1:48 pm then sells 2 times that amount at 1:52, or 9826 shares.
In the next 2 transactions, it catches up, buying an excess , 9819 shares then later selling 4906 , bringing us back down to 0 shares held

Since this is done at a different time then intended, the prices vary and the results will too.

Any idea why this happens? One solution is to use a present amount of shares, calculated never to put us into a margin situation, and stop using "order_target_percent". But perhaps I'm dong something else wrong.

Forgot to attach the snapshot snapshot

order_target type functions do not take into account any open orders. If you are doing them quickly in succession, especially in backtesting, they can stack up and lead to unexpected results. Most people recommend not using that function if there are still outstanding open orders for that sid.

Got it. Thanks