Add new handling of acquired/sold dates
This commit is contained in:
parent
932fd06f71
commit
8cb809bbb2
5 changed files with 93 additions and 11 deletions
57
README.md
57
README.md
|
|
@ -14,6 +14,7 @@ pip install kalshi-csv
|
|||
- **Market Breakdown**: See performance by market category with trade counts, win rates, and net P&L
|
||||
- **Legacy Web Mode**: Browse your portfolio in a retro HTML 4.01 web interface compatible with older browsers (Netscape Navigator, IE 4+)
|
||||
- **Market Categorization**: Automatic categorization of tickers into 7 market types (Global Soccer, MLB, NPB, NBA Summer League, WNBA, S&P 500, Multivariate Events, Other Markets)
|
||||
- **Handling of Sold + Acquired Dates**: Instead of handling the aggregated Kalshi trades through approximated dates, we use `VARIOUS` to signal to the IRS that every single underlying transaction in that row independently satisfies the short-term holding period rule (one year or less), even though they were purchased at different times.
|
||||
|
||||
## Getting Your Transactions CSV
|
||||
|
||||
|
|
@ -163,8 +164,8 @@ Internal Tracked Net P&L: $+0.26
|
|||
Use these exact aggregates for a single-line summary entry:
|
||||
* Box to Check: Box C (Short-term, not reported on Form 1099-B)
|
||||
* (a) Description: Kalshi Event Contracts (Aggregate Summary)
|
||||
* (b) Date Acquired: 07/07/2026
|
||||
* (c) Date Sold: 07/08/2026
|
||||
* (b) Date Acquired: VARIOUS
|
||||
* (c) Date Sold: VARIOUS
|
||||
* (d) Gross Proceeds: $+2.50
|
||||
* (e) Cost or Other Basis: $2.24
|
||||
* (h) Gain or (Loss): $+0.26
|
||||
|
|
@ -286,6 +287,54 @@ for trade in recent:
|
|||
- `cost_basis`: Total cost basis
|
||||
- `gain_or_loss`: Net gain or loss
|
||||
|
||||
## Development & Testing
|
||||
|
||||
For developers who want to contribute or run the test suite:
|
||||
|
||||
### Installing Dependencies
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### Running Tests
|
||||
|
||||
The project uses pytest for testing. Run the full test suite:
|
||||
|
||||
```bash
|
||||
pytest
|
||||
```
|
||||
|
||||
Or with verbose output:
|
||||
|
||||
```bash
|
||||
pytest -v
|
||||
```
|
||||
|
||||
### Sample Test Data
|
||||
|
||||
The test suite uses sample data located at `tests/fixtures/sample.csv`. If you want to create this file manually or modify it for testing:
|
||||
|
||||
**File location**: `tests/fixtures/sample.csv`
|
||||
|
||||
```csv
|
||||
type,quantity_fp,market_ticker,side,entry_price_dollars,exit_price_dollars,open_fees_dollars,close_fees_dollars,realized_pnl_without_fees_dollars,realized_pnl_with_fees_dollars,close_timestamp,open_timestamp
|
||||
trade,1.00,TESTMARKET-WIN,yes,0.5000,1.0000,0.010000,0.020000,0.500000,0.470000,2026-07-07T12:19:57-04:00,2026-07-07T09:48:19-04:00
|
||||
trade,2.00,TESTMARKET-LOSS,yes,0.4000,0.0000,0.020000,0.000000,-0.800000,-0.820000,2026-07-07T12:56:23-04:00,2026-07-07T12:37:41-04:00
|
||||
trade,0.50,TESTMARKET-SMALL,no,0.6000,0.8000,0.010000,0.010000,0.100000,0.080000,2026-07-07T14:07:41-04:00,2026-07-07T12:26:45-04:00
|
||||
```
|
||||
|
||||
This sample contains 3 trades:
|
||||
- **TESTMARKET-WIN**: A winning trade (+$0.47 P&L with fees)
|
||||
- **TESTMARKET-LOSS**: A losing trade (-$0.82 P&L with fees)
|
||||
- **TESTMARKET-SMALL**: A small winning trade (+$0.08 P&L with fees)
|
||||
|
||||
You can also test this sample data directly with the CLI:
|
||||
|
||||
```bash
|
||||
kalshi-csv tests/fixtures/sample.csv
|
||||
```
|
||||
|
||||
## IRS Form 8949
|
||||
|
||||
Kalshi event contracts are typically reported on **IRS Form 8949, Box C** (short-term transactions not reported on Form 1099-B). The tool calculates:
|
||||
|
|
@ -300,9 +349,9 @@ Use the aggregate summary for a single-line entry on Form 8949, or export to a f
|
|||
|
||||
## Source Code
|
||||
|
||||
This project is hosted in two locations:
|
||||
This project is hosted in two locations, GitHub and my home Forgejo server, contributions are easiest through GitHub, but you are welcome to clone from my Forgejo as well:
|
||||
- **GitHub**: [https://github.com/MARKMENTAL/kalshi-csv](https://github.com/MARKMENTAL/kalshi-csv)
|
||||
- **Codeberg**: [https://codeberg.org/markmental/kalshi-csv](https://codeberg.org/markmental/kalshi-csv)
|
||||
- **MentalNet Forgejo v2**: [https://mentalnet.xyz/forgejo-v2/markmental/kalshi-csv](https://mentalnet.xyz/forgejo-v2/markmental/kalshi-csv)
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ keywords = ["kalshi", "csv", "tax", "irs", "form-8949"]
|
|||
|
||||
[project.urls]
|
||||
Homepage = "https://github.com/MARKMENTAL/kalshi-csv"
|
||||
Source = "https://codeberg.org/markmental/kalshi-csv"
|
||||
Source = "https://mentalnet.xyz/forgejo-v2/markmental/kalshi-csv"
|
||||
Issues = "https://github.com/MARKMENTAL/kalshi-csv/issues"
|
||||
|
||||
[project.scripts]
|
||||
|
|
|
|||
33
requirements.txt
Normal file
33
requirements.txt
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
build==1.5.0
|
||||
certifi==2026.6.17
|
||||
cffi==2.1.0
|
||||
charset-normalizer==3.4.9
|
||||
cryptography==49.0.0
|
||||
docutils==0.23
|
||||
id==1.6.1
|
||||
idna==3.18
|
||||
iniconfig==2.3.0
|
||||
jaraco.classes==3.4.0
|
||||
jaraco.context==6.1.2
|
||||
jaraco.functools==4.6.0
|
||||
jeepney==0.9.0
|
||||
-e git+https://codeberg.org/markmental/kalshi-csv.git@f7171c025c23d8d46931042f6dba48c4e6beeda9#egg=kalshi_csv
|
||||
keyring==25.7.0
|
||||
markdown-it-py==4.2.0
|
||||
mdurl==0.1.2
|
||||
more-itertools==11.1.0
|
||||
nh3==0.3.6
|
||||
packaging==26.2
|
||||
pluggy==1.6.0
|
||||
pycparser==3.0
|
||||
Pygments==2.20.0
|
||||
pyproject_hooks==1.2.0
|
||||
pytest==9.1.1
|
||||
readme_renderer==45.0
|
||||
requests==2.34.2
|
||||
requests-toolbelt==1.0.0
|
||||
rfc3986==2.0.0
|
||||
rich==15.0.0
|
||||
SecretStorage==3.5.0
|
||||
twine==6.2.0
|
||||
urllib3==2.7.0
|
||||
|
|
@ -175,8 +175,8 @@ def main():
|
|||
print("Use these exact aggregates for a single-line summary entry:")
|
||||
print(f" * Box to Check: {color_white('Box C', no_color)} (Short-term, not reported on Form 1099-B)")
|
||||
print(f" * (a) Description: {irs['description']}")
|
||||
print(f" * (b) Date Acquired: {irs['date_acquired']}")
|
||||
print(f" * (c) Date Sold: {irs['date_sold']}")
|
||||
print(f" * (b) Date Acquired: VARIOUS")
|
||||
print(f" * (c) Date Sold: VARIOUS")
|
||||
print(f" * (d) Gross Proceeds: {format_currency_color(irs['gross_proceeds'], no_color)}")
|
||||
print(f" * (e) Cost or Other Basis: {color_cyan(f'${irs['cost_basis']:.2f}', no_color)}")
|
||||
print(f" * (h) Gain or (Loss): {format_currency_color(irs['gain_or_loss'], no_color)}")
|
||||
|
|
@ -189,8 +189,8 @@ def main():
|
|||
f.write("Use these exact aggregates for a single-line summary entry:\n")
|
||||
f.write(f" * Box to Check: Box C (Short-term, not reported on Form 1099-B)\n")
|
||||
f.write(f" * (a) Description: {irs['description']}\n")
|
||||
f.write(f" * (b) Date Acquired: {irs['date_acquired']}\n")
|
||||
f.write(f" * (c) Date Sold: {irs['date_sold']}\n")
|
||||
f.write(f" * (b) Date Acquired: VARIOUS\n")
|
||||
f.write(f" * (c) Date Sold: VARIOUS\n")
|
||||
f.write(f" * (d) Gross Proceeds: ${irs['gross_proceeds']:.2f}\n")
|
||||
f.write(f" * (e) Cost or Other Basis: ${irs['cost_basis']:.2f}\n")
|
||||
f.write(f" * (h) Gain or (Loss): ${irs['gain_or_loss']:.2f}\n")
|
||||
|
|
|
|||
|
|
@ -113,12 +113,12 @@ def render_portfolio_html(kalshi, csv_filename):
|
|||
<tr><td colspan="2"><hr size="1" color="#E0E0E0" noshade></td></tr>
|
||||
<tr>
|
||||
<td align="left"><font face="Geneva, Verdana, sans-serif" size="1" color="#666666">Date Acquired:</font></td>
|
||||
<td align="left"><font face="Courier New, Courier, monospace" size="2">{html.escape(irs['date_acquired'])}</font></td>
|
||||
<td align="left"><font face="Courier New, Courier, monospace" size="2">VARIOUS</font></td>
|
||||
</tr>
|
||||
<tr><td colspan="2"><hr size="1" color="#E0E0E0" noshade></td></tr>
|
||||
<tr>
|
||||
<td align="left"><font face="Geneva, Verdana, sans-serif" size="1" color="#666666">Date Sold:</font></td>
|
||||
<td align="left"><font face="Courier New, Courier, monospace" size="2">{html.escape(irs['date_sold'])}</font></td>
|
||||
<td align="left"><font face="Courier New, Courier, monospace" size="2">VARIOUS</font></td>
|
||||
</tr>
|
||||
<tr><td colspan="2"><hr size="1" color="#E0E0E0" noshade></td></tr>
|
||||
<tr>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue