Graeme22 / tastyworks-cli

Easy to use command line interface for Tastyworks!
MIT License
15 stars 2 forks source link

Fails Inelegantly When Opening Trade Not Found #25

Closed GenusGeoff closed 2 years ago

GenusGeoff commented 3 years ago

This worked just fine for my personal taxable account, but failing to find an opening trade caused an ugly error and dump.

Traceback (most recent call last):
  File "C:\Users\DailyUse\anaconda3\lib\runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Users\DailyUse\anaconda3\lib\runpy.py", line 87, in _run_code
    exec(code, run_globals)
  File "C:\Users\DailyUse\anaconda3\Scripts\tw.exe\__main__.py", line 7, in <module>
  File "C:\Users\DailyUse\anaconda3\lib\site-packages\src\app.py", line 28, in main
    app(_anyio_backend='asyncio')
  File "C:\Users\DailyUse\anaconda3\lib\site-packages\asyncclick\core.py", line 1159, in __call__
    return anyio.run(self._main, main, args, kwargs, **({"backend":_anyio_backend} if _anyio_backend is not None else {}))
  File "C:\Users\DailyUse\anaconda3\lib\site-packages\anyio\_core\_eventloop.py", line 56, in run
    return asynclib.run(func, *args, **backend_options)  # type: ignore
  File "C:\Users\DailyUse\anaconda3\lib\site-packages\anyio\_backends\_asyncio.py", line 230, in run
    return native_run(wrapper(), debug=debug)
  File "C:\Users\DailyUse\anaconda3\lib\asyncio\runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "C:\Users\DailyUse\anaconda3\lib\asyncio\base_events.py", line 616, in run_until_complete
    return future.result()
  File "C:\Users\DailyUse\anaconda3\lib\site-packages\anyio\_backends\_asyncio.py", line 225, in wrapper
    return await func(*args)
  File "C:\Users\DailyUse\anaconda3\lib\site-packages\asyncclick\core.py", line 1162, in _main
    return await main(*args, **kwargs)
  File "C:\Users\DailyUse\anaconda3\lib\site-packages\asyncclick\core.py", line 1083, in main
    rv = await self.invoke(ctx)
  File "C:\Users\DailyUse\anaconda3\lib\site-packages\asyncclick\core.py", line 1693, in invoke
    return await _process_result(await sub_ctx.command.invoke(sub_ctx))
  File "C:\Users\DailyUse\anaconda3\lib\site-packages\asyncclick\core.py", line 1429, in invoke
    return await ctx.invoke(self.callback, **ctx.params)
  File "C:\Users\DailyUse\anaconda3\lib\site-packages\asyncclick\core.py", line 783, in invoke
    rv = await rv
  File "C:\Users\DailyUse\anaconda3\lib\site-packages\src\plot\commands.py", line 43, in plot
    pf = Portfolio(petl.data(table), net_liq=netliq)
  File "C:\Users\DailyUse\anaconda3\lib\site-packages\src\plot\plot.py", line 61, in __init__
    self._calculate()
  File "C:\Users\DailyUse\anaconda3\lib\site-packages\src\plot\plot.py", line 232, in _calculate
    raise TastyworksCLIError(f'Closing trade present but opening trade missing for trade:\n{t}')
src.utils.TastyworksCLIError: Closing trade present but opening trade missing for trade:
2017-05-19: VNQ x5.0 at $409.8

@Graeme22

Graeme22 commented 3 years ago

Thanks for posting. Let me take a look.

Graeme22 commented 3 years ago

Would you be willing to send me your transaction history CSV? I'll need more context to debug this.

Graeme22 commented 3 years ago

You could just send me the VNQ related rows, perhaps.

GenusGeoff commented 3 years ago

Okay, so this looks like I had a few shares in an ACAT transfer. It's a pretty edge case, but there might need to be some kind of handling for it as the script would be otherwise never usable for that account.

ACAT

Graeme22 commented 3 years ago

Could I get the CSV from tastyworks? That has the transactions formatted the same way as the API.

Graeme22 commented 3 years ago

Good to know what the source of the problem is though.

GenusGeoff commented 3 years ago

Yes, I agree completely. I would have provided that, but I'm not sure how that's done. I didn't see a link on the TastyWorks.com website.

Graeme22 commented 3 years ago

Afaik you have to use the client. Go to transactions > choose custom date range > enter date before creation of the account > scroll to bottom to load all transactions. Then click CSV to export.

GenusGeoff commented 3 years ago

Here you go, my apologies for not finding this sooner.

NOTE: Had to rename it to .txt because GitHub doesn't support .csv as an extension.

tastyworks_transactions_x9999_2015-08-01_2021-08-05.txt

Graeme22 commented 3 years ago

Ok I think I know what it is. What date did you open transfer your account? My guess is this line from plot/commands.py doesn't fetch all the transactions because the ACAT dates some of them before the creation of your account:

history = await acc.get_history(sesh, params={
    'start-date': start_date.isoformat() + 'Z',
    'end-date': datetime.now().isoformat() + 'Z',
})

Specifically, the entry of 2017/04/18 may be before that creation date.

GenusGeoff commented 3 years ago

I don't actually know when I transferred the account, but it was somewhere around that time. But, there isn't an entry for the actual transfer/opening of the account in the CSV. I moved the dates back to 2015 which is definitely before the acct opening and there aren't any other entries than what I've provided.

There might need to be some provision to provide a cost basis and/or just disclude certain entries in the calculation. It may even be a nice feature to simply have the user select a start/end date for the charting. But, YMMV.

Graeme22 commented 3 years ago

What I really want to do is just fetch ALL transactions, regardless of date. Custom date range can't be done because closing trades could occur without an opening trade present. The plotting method basically plays back all transactions and figures out when profits/losses are realized, which requires the entire transaction history.

I'll leave this open until I find a solution for that. This sounds like an edge case assuming the problem is what I'm guessing. I'll let you know if I come up with something so we can verify it does actually solve the problem.

Graeme22 commented 3 years ago

@GenusGeoff could you see if it works with the current main branch?

GenusGeoff commented 3 years ago

I ran pip3 to update it. I want to provide this to make sure that I'm using the right version:

Name: tastyworks-cli Version: 0.3.0 Summary: An easy-to-use command line interface for Tastyworks! Home-page: https://github.com/Graeme22/tastyworks-cli/ Author: Graeme Holliday Author-email: graeme.holliday@pm.me License: MIT Location: c:\users\dailyuse\anaconda3\lib\site-packages Requires: matplotlib, anyio, petl, QuantLib, pandas, asyncclick, tastyworks-api, python-dateutil Required-by:

And, the short answer is no. This isn't working just yet. I used tw plot (the Readme says to use twcli plot but that doesn't lineup with the current installation.

Traceback (most recent call last): File "C:\Users\DailyUse\anaconda3\lib\runpy.py", line 194, in _run_module_as_main return _run_code(code, main_globals, None, File "C:\Users\DailyUse\anaconda3\lib\runpy.py", line 87, in _run_code exec(code, run_globals) File "C:\Users\DailyUse\anaconda3\Scripts\tw.exe\__main__.py", line 7, in <module> File "C:\Users\DailyUse\anaconda3\lib\site-packages\src\app.py", line 28, in main app(_anyio_backend='asyncio') File "C:\Users\DailyUse\anaconda3\lib\site-packages\asyncclick\core.py", line 1159, in __call__ return anyio.run(self._main, main, args, kwargs, **({"backend":_anyio_backend} if _anyio_backend is not None else {})) File "C:\Users\DailyUse\anaconda3\lib\site-packages\anyio\_core\_eventloop.py", line 56, in run return asynclib.run(func, *args, **backend_options) # type: ignore File "C:\Users\DailyUse\anaconda3\lib\site-packages\anyio\_backends\_asyncio.py", line 230, in run return native_run(wrapper(), debug=debug) File "C:\Users\DailyUse\anaconda3\lib\asyncio\runners.py", line 44, in run return loop.run_until_complete(main) File "C:\Users\DailyUse\anaconda3\lib\asyncio\base_events.py", line 616, in run_until_complete return future.result() File "C:\Users\DailyUse\anaconda3\lib\site-packages\anyio\_backends\_asyncio.py", line 225, in wrapper return await func(*args) File "C:\Users\DailyUse\anaconda3\lib\site-packages\asyncclick\core.py", line 1162, in _main return await main(*args, **kwargs) File "C:\Users\DailyUse\anaconda3\lib\site-packages\asyncclick\core.py", line 1083, in main rv = await self.invoke(ctx) File "C:\Users\DailyUse\anaconda3\lib\site-packages\asyncclick\core.py", line 1693, in invoke return await _process_result(await sub_ctx.command.invoke(sub_ctx)) File "C:\Users\DailyUse\anaconda3\lib\site-packages\asyncclick\core.py", line 1429, in invoke return await ctx.invoke(self.callback, **ctx.params) File "C:\Users\DailyUse\anaconda3\lib\site-packages\asyncclick\core.py", line 783, in invoke rv = await rv File "C:\Users\DailyUse\anaconda3\lib\site-packages\src\plot\commands.py", line 43, in plot pf = Portfolio(petl.data(table), net_liq=netliq) File "C:\Users\DailyUse\anaconda3\lib\site-packages\src\plot\plot.py", line 61, in __init__ self._calculate() File "C:\Users\DailyUse\anaconda3\lib\site-packages\src\plot\plot.py", line 232, in _calculate raise TastyworksCLIError(f'Closing trade present but opening trade missing for trade:\n{t}') src.utils.TastyworksCLIError: Closing trade present but opening trade missing for trade: 2017-05-19: VNQ x5.0 at $409.8

Graeme22 commented 3 years ago

I did not publish it to pip, could you build the current main branch from source? Instructions are on the README.

Graeme22 commented 2 years ago

Closing as stale, please reopen if the issue persists.