KapJI / capital-gains-calculator

UK capital gains tax calculator which supports transaction history from different brokers
MIT License
124 stars 48 forks source link

AssertionError: `same_day_quantity <= acquisition_quantity` #460

Closed m01 closed 8 months ago

m01 commented 9 months ago

Hi, Firstly, thanks for open sourcing this tool! Secondly, this bug is not something that's causing me "Jan 31 worries". Thirdly, the raw format is quite handy for debugging and excluding trading-platform-specific parser issues, thanks for that, too.

With the following raw format, I manage to trigger an assertion error:

2023-06-30,SELL,STOCK,100,100.00,1.0,USD
2023-06-30,STOCK_ACTIVITY,STOCK,50,99.00,1.0,USD
2023-06-25,SELL,STOCK,30,100.00,1.0,USD
2023-01-01,STOCK_ACTIVITY,STOCK,500,101.10,1.0,USD

I can't see anything particularly wrong with the transaction data (it's a minimal & anonymised repro of real data, and if I exclude the sale on 2023-06-25 then the tool runs fine).

repro:

python -m cgt_calc.main --year 2023 --exchange-rates-file ./hmrc_fx.csv --report ./raw_test.pdf --raw ./raw_test.csv

Output:

INFO: No schwab file provided
INFO: No schwab Equity Award JSON file provided
INFO: No trading212 folder provided
INFO: No mssb folder provided
INFO: No sharesight file provided
First pass completed
Final portfolio:
  STOCK: 419.00
Final balance:
  Unknown: 13098.00 (USD)
Dividends: £0.00
Dividend taxes: £0.00
Interest: £0.00
Disposal proceeds: £10589.62

Traceback (most recent call last):
  File "<frozen runpy>", line 198, in _run_module_as_main
  File "<frozen runpy>", line 88, in _run_code
  File "/home/whatever/capital-gains-calculator/cgt_calc/main.py", line 717, in <module>
    init()
  File "/home/whatever/capital-gains-calculator/cgt_calc/main.py", line 713, in init
    sys.exit(main())
             ^^^^^^
  File "/home/whatever/capital-gains-calculator/cgt_calc/main.py", line 696, in main
    report = calculator.calculate_capital_gain(acquisition_list, disposal_list)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/whatever/capital-gains-calculator/cgt_calc/main.py", line 587, in calculate_capital_gain
    ) = self.process_disposal(
        ^^^^^^^^^^^^^^^^^^^^^^
  File "/home/whatever/capital-gains-calculator/cgt_calc/main.py", line 434, in process_disposal
    assert same_day_quantity <= acquisition_quantity
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AssertionError

This is with the current HEAD revision (339b854983075053cdecadcbd90282fc8282b94f), but I don't think the issue is very new as I also hit it with da4a4da676ecf.

m01 commented 8 months ago

I've done some debugging to try to investigate this issue. To simplify things further I changed the currencies to GBP in my repro example, i.e.:

2023-06-30,SELL,STOCK,100,100.00,1.0,GBP
2023-06-30,STOCK_ACTIVITY,STOCK,50,99.00,1.0,GBP
2023-06-25,SELL,STOCK,30,100.00,1.0,GBP
2023-01-01,STOCK_ACTIVITY,STOCK,500,101.10,1.0,GBP

Here's what seems to be happening:

  1. The "first pass" (calculator.convert_to_hmrc_transactions) runs fine. You end up with the following:
    {datetime.date(2023, 1, 1): {'STOCK': HmrcTransactionData(quantity=Decimal('500'),
                                                          amount=Decimal('50550.00'),
                                                          fees=Decimal('1.0'))},
    datetime.date(2023, 6, 30): {'STOCK': HmrcTransactionData(quantity=Decimal('50'),
                                                           amount=Decimal('4950.00'),
                                                           fees=Decimal('1.0'))}}
    ipdb> pp disposal_list
    {datetime.date(2023, 6, 25): {'STOCK': HmrcTransactionData(quantity=Decimal('30'),
                                                           amount=Decimal('2999.00'),
                                                           fees=Decimal('1.0'))},
    datetime.date(2023, 6, 30): {'STOCK': HmrcTransactionData(quantity=Decimal('100'),
                                                           amount=Decimal('9999.00'),
                                                           fees=Decimal('1.0'))}}
  2. You start the second, capital gains calculation pass (calculator.calculate_capital_gain) and going through days.
  3. 2023-01-01,STOCK_ACTIVITY,STOCK,500,101.10,1.0,GBP is processed, and you end up with the following calculation_entries: [<CalculationEntry SECTION 104, quantity: 500, disposal proceeds: -50550.00, allowable cost: 50550.00, fees: 1.0, gain: 0>]
  4. 2023-06-25,SELL,STOCK,30,100.00,1.0,GBP is processed.
vmartinv commented 8 months ago

In your case there should be applied only the same day rule on 2023-06-30, then the rest is just 104. I believe I have the fix but would you take a look at the attached report and double check is correct? raw_test.pdf

m01 commented 8 months ago

Disclaimer: I'm not a financial advisor/accountant.

In your case there should be applied only the same day rule on 2023-06-30, then the rest is just 104.

This is my understanding as well. (For completeness, if there was another acquisition on, say, 2023-07-01 then I guess there might be some more B&B?)

I believe I have the fix

Nice!

look at the attached report and double check is correct?

Assuming our understanding above is correct, the report should have the same numbers as if we ran it on the following data, where I moved the sale from 2023-06-25 to 2023-05-25 to be outside of the 30 day window, avoiding triggering the assert:

2023-06-30,SELL,STOCK,100,100.00,1.0,GBP
2023-06-30,STOCK_ACTIVITY,STOCK,50,99.00,1.0,GBP
2023-05-25,SELL,STOCK,30,100.00,1.0,GBP
2023-01-01,STOCK_ACTIVITY,STOCK,500,101.10,1.0,GBP

And indeed the numbers seem to match, so it seems consistent.

In terms of correctness I'm still working on understanding a few things but I don't think those are specific to this issue.

vmartinv commented 8 months ago

Thanks for the clarification @m01, I created a PR with the fix: #473

KapJI commented 8 months ago

Closed by #473