-
Notifications
You must be signed in to change notification settings - Fork 210
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Question about shares and pnl number in "result.trades" #80
Comments
Yes, this is intentional since calc_target_shares is generic and can be used to calculate buy_shares or sell_shares. You will need to pass in the previous day's open price using self.open[-1] if you intend to use the open price. |
Hi @edtechre, Well, my intention is: I want to buy or sell a security tomorrow at the open price, once I found a calculated signal based on today's close price appears. For example, on 2023/12/5, I'm backtesting a strategy on a security data from 2008/1/1 to 2008/3/1, now I found close price is cross up MA20 on 2008/1/10, and I want to buy this security at the open price of very next day (2008/1/11). How would I do that? And what's the point show the shares/pnl which doesn't match with the entry/exit price in the result.trades? There is another question: |
Hi @none2003, Sorry that I did not previously address your concerns. I misunderstood your original posts and it seems there are two different issues here:
I believe the discrepancy is due to rounding. My suspicion is that the entry price is not 887.064 but is some some other floating point value. Note that the values in result.trades are rounded up to the nearest cent before they are displayed. If you can email me your data with the symbols anonymized, I can take a look and verify this.
This is done by setting ctx.buy_fill_price = PriceType.OPEN.
They serve different purposes, calc_target_shares is a helper function for calculating the number of shares to buy or sell. Passing in self.open[-1] will calculate the number of shares based on the last completed bar's open price. Setting ctx.buy_fill_price = PriceType.OPEN will set the fill price to the open price of the next bar. It sounds like you want to calculate the number of shares (i.e. 20% of your portfolio) to a symbol using the next bar's open price. But this is not supported because it would introduce lookahead bias into your strategy, and would likely be unrealistic to implement in a real strategy anyway due to slippage. |
I uploaded an example notebook. This strategy is simple:
The very first buy order is filled with open price 2645.10 of 2017-12-01, this is consistent with the settings (ctx.buy_fill_price = PriceType.OPEN). However, the "shares" number is 37770, I think it should be 100000000 / 2645.10009765625 = 37805. The following sell order is filled with open price 2741.06 of 2018-02-05, this is also consistent with the settings (ctx.sell_fill_price = PriceType.OPEN). Let's assume share number 37770 were right, the pnl should be 37770 * 2741.06005859375 - 100000000 = 3529838.4131. And if using share number 37805, that will be 37805 * 2741.06005859375 - 100000000 = 3625775.5151. But in result.order, it gives 3624407.72, largely differs with both numbers above given. |
Thank you for providing a notebook. However, I will need data to be able to debug.
I am not sure where 100000000 comes from. The PnL is not calculated using your initial cash, it is calculated as the PnL from entry to exit:
If config.enable_fractional_shares was not set to true, then not all of your initial cash (100000000) will be invested since only whole shares will be traded. |
Please download and check the notebook, I used Yfinance to get "^SPX" data live inside notebook, like pyb example notebooks. |
The calculations there look correct to me and is consistent with my explanation of calc_target_shares and buy_fill_price above.
By default, this uses the close price of the last completed bar. It is never the fill price of the next bar, because that would introduce lookahead bias. You can't calculate the number of shares to buy based on a future price you haven't seen yet. For the first trade, close price = 2647.580078125 Then the actual open price is 2645.100098. The exit price is 2741.060059. This is consistent with the dataframe before the values are quantized by rounding up to the nearest cent. |
OK, I see. Thank you for the detailed explanation. |
Hi @edtechre,
I noticed a weirdness about some number in result.trades.
Steps to reproduce:
The first two rows of "result.trades" look like this:
The first shares value is 112694 rather than 100000000 / 887.064(entry price) = 112731.
Personally, I think 112731 is right.
And even shares value of 112694 were correct, shouldn't the pnl be 112694 * 1012.578(exit price) - 100000000 = 14111465.13?
Ideally, I think pnl should be 112731 * 1012.578 - 100000000 = 14148930.52
I did some digging in source code, and I found this:
It seems the execution price when buying is the price of last bar, even "ctx.buy_fill_price = PriceType.OPEN" has been set. Is this intentional?
I apologize for not having enough time to find the code that calculating pnl.
The text was updated successfully, but these errors were encountered: