Skip to content

Commit 21b32f6

Browse files
authored
overload to simplify classmethods (#230)
* overload to simplify classmethods * update docs, split watchlist into public/private * fix tests * update workflow
1 parent 973dd4d commit 21b32f6

19 files changed

Lines changed: 689 additions & 497 deletions

.github/workflows/python-app.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,6 @@ jobs:
3131
env:
3232
TT_USERNAME: ${{ secrets.TT_USERNAME }}
3333
TT_PASSWORD: ${{ secrets.TT_PASSWORD }}
34+
TT_USERNAME_SANDBOX: ${{ secrets.TT_USERNAME_SANDBOX }}
35+
TT_PASSWORD_SANDBOX: ${{ secrets.TT_PASSWORD_SANDBOX }}
3436
TT_ACCOUNT: ${{ secrets.TT_ACCOUNT }}

README.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ A simple, reverse-engineered SDK for Tastytrade built on their (now mostly publi
2121
> Want to see the SDK in action? Check out [tastytrade-cli](https://github.com/tastyware/tastytrade-cli), a CLI for Tastytrade that showcases many of the SDK's features.
2222
2323
> [!NOTE]
24-
> Do you use TradeStation? We're building a [brand-new SDK](https://github.com/tastyware/tradestation) for TS users, with many of the same features!
24+
> Want to build an advanced trading system? Check out [streaQ](https://github.com/tastyware/streaq), an async job queuing library for Python that's perfect for complex applications!
2525
2626
## Installation
2727

@@ -66,7 +66,7 @@ Note that this is asynchronous code, so you can't run it as is unless you're usi
6666
```python
6767
from tastytrade import Account
6868

69-
account = Account.get_accounts(session)[0]
69+
account = Account.get(session)[0]
7070
positions = account.get_positions(session)
7171
print(positions[0])
7272
```
@@ -75,6 +75,18 @@ print(positions[0])
7575
>>> CurrentPosition(account_number='5WX01234', symbol='IAU', instrument_type=<InstrumentType.EQUITY: 'Equity'>, underlying_symbol='IAU', quantity=Decimal('20'), quantity_direction='Long', close_price=Decimal('37.09'), average_open_price=Decimal('37.51'), average_yearly_market_close_price=Decimal('37.51'), average_daily_market_close_price=Decimal('37.51'), multiplier=1, cost_effect=<PriceEffect.CREDIT: 'Credit'>, is_suppressed=False, is_frozen=False, realized_day_gain=Decimal('7.888'), realized_day_gain_date=datetime.date(2023, 5, 19), realized_today=Decimal('-0.512'), realized_today_date=datetime.date(2023, 5, 19), created_at=datetime.datetime(2023, 3, 31, 14, 38, 32, 58000, tzinfo=datetime.timezone.utc), updated_at=datetime.datetime(2023, 5, 19, 16, 56, 51, 920000, tzinfo=datetime.timezone.utc), mark=None, mark_price=None, restricted_quantity=Decimal('0'), expires_at=None, fixing_price=None, deliverable_type=None)
7676
```
7777

78+
## Sync/async wrappers
79+
80+
The code from above can be rewritten asynchronously:
81+
82+
```python
83+
from tastytrade import Account
84+
85+
account = (await Account.a_get(session))[0]
86+
positions = await account.a_get_positions(session)
87+
print(positions[0])
88+
```
89+
7890
## Placing an order
7991

8092
```python
@@ -83,8 +95,8 @@ from tastytrade import Account
8395
from tastytrade.instruments import Equity
8496
from tastytrade.order import NewOrder, OrderAction, OrderTimeInForce, OrderType
8597

86-
account = Account.get_account(session, '5WX01234')
87-
symbol = Equity.get_equity(session, 'USO')
98+
account = Account.get(session, '5WX01234')
99+
symbol = Equity.get(session, 'USO')
88100
leg = symbol.build_leg(Decimal('5'), OrderAction.BUY_TO_OPEN) # buy to open 5 shares
89101

90102
order = NewOrder(

docs/account-streamer.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Here's an example of setting up an account streamer to continuously wait for eve
1414
from tastytrade import Account, AlertStreamer, Watchlist
1515
1616
async with AlertStreamer(session) as streamer:
17-
accounts = Account.get_accounts(session)
17+
accounts = Account.get(session)
1818
1919
# updates to balances, orders, and positions
2020
await streamer.subscribe_accounts(accounts)
@@ -33,7 +33,7 @@ Probably the most important information the account streamer handles is order fi
3333
from tastytrade.order import PlacedOrder
3434
3535
async with AlertStreamer(session) as streamer:
36-
accounts = Account.get_accounts(session)
36+
accounts = Account.get(session)
3737
await streamer.subscribe_accounts(accounts)
3838
3939
async for order in streamer.listen(PlacedOrder):

docs/accounts.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@ The easiest way to get an account is to grab all accounts associated with a spec
88
.. code-block:: python
99
1010
from tastytrade import Account
11-
accounts = Account.get_accounts(session)
11+
accounts = Account.get(session)
1212
1313
You can also get a specific account by its unique ID:
1414

1515
.. code-block:: python
1616
17-
account = Account.get_account(session, '5WX01234')
17+
account = Account.get(session, '5WX01234')
1818
1919
The ``get_balances`` function can be used to obtain information about the current buying power and cash balance:
2020

@@ -58,4 +58,4 @@ We can also view portfolio P/L over time (and even plot it!):
5858

5959
Accounts are needed to place, replace, and delete orders. See more in :doc:`Orders <orders>`.
6060

61-
There are many more things you can do with an ``Account`` object--check out the SDK Reference section!
61+
There are many more things you can do with an ``Account`` object--check out the SDK Reference section!

docs/data-streamer.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Once you've created the streamer, you can subscribe/unsubscribe to events, like
3131
await streamer.subscribe(Quote, subs_list)
3232
quotes = {}
3333
async for quote in streamer.listen(Quote):
34-
quotes[quote.eventSymbol] = quote
34+
quotes[quote.event_symbol] = quote
3535
if len(quotes) >= len(subs_list):
3636
break
3737
print(quotes)

docs/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ A simple, reverse-engineered, sync/async SDK for Tastytrade built on their (now
2323
Want to see the SDK in action? Check out `tastytrade-cli <https://github.com/tastyware/tastytrade-cli>`_, a CLI for Tastytrade that showcases many of the SDK's features.
2424

2525
.. note::
26-
Do you use TradeStation? We're building a `brand-new SDK <https://github.com/tastyware/tradestation>`_ for TS users, with many of the same features!
26+
Want to build an advanced trading system? Check out `streaQ <https://github.com/tastyware/streaq>`_, an async job queuing library for Python that's perfect for complex applications!
2727

2828
.. toctree::
2929
:maxdepth: 2

docs/instruments.rst

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ Initialization
99

1010
Instruments follow a basic schema for initialization. To create an instrument(s), use the classmethods for the desired type of instrument:
1111

12-
- ``Cryptocurrency.get_cryptocurrency()``, ``Cryptocurrency.get_cryptocurrencies()``
13-
- ``Equity.get_equity()``, ``Equity.get_equities()``
14-
- ``Future.get_future()``, ``Future.get_futures()``
15-
- ``Option.get_option()``, ``Option.get_options()``
16-
- ``FutureOption.get_future_option()``, ``FutureOption.get_future_options()``
12+
- ``Cryptocurrency.get()``
13+
- ``Equity.get()``
14+
- ``Future.get()``
15+
- ``Option.get()``
16+
- ``FutureOption.get()``
1717

1818
These functions take the session object as the first parameter, and the symbol (or list of symbols) as the second.
1919
Note that ETFs and indices are treated as equities for the purposes of the API.
@@ -22,9 +22,9 @@ Note that ETFs and indices are treated as equities for the purposes of the API.
2222
2323
from tastytrade.instruments import Equity, FutureOption
2424
25-
equities = Equity.get_equities(session, ['SPY', 'AAPL'])
25+
equities = Equity.get(session, ['SPY', 'AAPL'])
2626
print(equities[0].is_etf, equities[0].description)
27-
future_option = FutureOption.get_future_option(session, './GCJ4 OG4G4 240223P1915')
27+
future_option = FutureOption.get(session, './GCJ4 OG4G4 240223P1915')
2828
print(future_option.exchange)
2929
3030
>>> (False, 'APPLE INC')
@@ -57,7 +57,7 @@ Alternatively, ``NestedOptionChain`` and ``NestedFutureOptionChain`` provide a s
5757
5858
from tastytrade.instruments import NestedOptionChain
5959
60-
chain = NestedOptionChain.get_chain(session, 'SPY')
60+
chain = NestedOptionChain.get(session, 'SPY')
6161
print(chain.expirations[0].strikes[0])
6262
6363
>>> Strike(strike_price=Decimal('437.0'), call='SPY 240417C00437000', put='SPY 240417P00437000', call_streamer_symbol='.SPY240417C437', put_streamer_symbol='.SPY240417P437')

docs/orders.rst

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ Placing an order
1111
from tastytrade.instruments import Equity
1212
from tastytrade.order import *
1313
14-
account = Account.get_account(session, '5WX01234')
15-
symbol = Equity.get_equity(session, 'USO')
14+
account = Account.get(session, '5WX01234')
15+
symbol = Equity.get(session, 'USO')
1616
leg = symbol.build_leg(Decimal('5'), OrderAction.BUY_TO_OPEN) # buy to open 5 shares
1717
1818
order = NewOrder(
@@ -71,7 +71,7 @@ To create an OTOCO order, you need an entry point order, a stop loss order, and
7171
from tastytrade.instruments import Equity
7272
from tastytrade.order import *
7373
74-
symbol = Equity.get_equity(session, 'AAPL')
74+
symbol = Equity.get(session, 'AAPL')
7575
opening = symbol.build_leg(Decimal(1), OrderAction.BUY_TO_OPEN) # buy to open 1 share
7676
closing = symbol.build_leg(Decimal(1), OrderAction.SELL_TO_CLOSE) # sell to close 1 share
7777
@@ -103,7 +103,7 @@ An OCO order is similar, but has no trigger order. It's used to add a profit-tak
103103

104104
.. code-block:: python
105105
106-
symbol = Equity.get_equity(session, 'SPY')
106+
symbol = Equity.get(session, 'SPY')
107107
closing = symbol.build_leg(Decimal(10), OrderAction.SELL_TO_CLOSE) # sell to close 10 shares
108108
109109
oco = NewComplexOrder(
@@ -135,7 +135,7 @@ Notional orders are slightly different from normal orders. Since the market will
135135

136136
.. code-block:: python
137137
138-
symbol = Equity.get_equity(session, 'AAPL')
138+
symbol = Equity.get(session, 'AAPL')
139139
order = NewOrder(
140140
time_in_force=OrderTimeInForce.DAY,
141141
order_type=OrderType.NOTIONAL_MARKET,

docs/sync-async.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Let's see how this looks:
1010
from tastytrade Account, Session
1111
session = Session(username, password)
1212
# using sync implementation
13-
accounts = Account.get_accounts(session)
13+
accounts = Account.get(session)
1414
1515
The async implementation is similar:
1616

@@ -19,7 +19,7 @@ The async implementation is similar:
1919
from tastytrade Account, Session
2020
session = Session(username, password)
2121
# using async implementation
22-
accounts = await Account.a_get_accounts(session)
22+
accounts = await Account.a_get(session)
2323
2424
That's it! All sync methods have a parallel async method that starts with `a_`.
2525

docs/watchlists.rst

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
Watchlists
22
==========
33

4-
In this example assume ``MyWatchlist`` is an exising watchlist we want to modify.
5-
64
To use watchlists you'll need a production session:
75

86
.. code-block:: python
97
108
from tastytrade import Session
119
session = Session(user, password)
1210
13-
Now we can fetch the watchlist:
11+
Let's fetch an existing watchlist:
1412

1513
.. code-block:: python
1614
17-
from tastytrade import Watchlist
18-
watchlist = Watchlist.get_private_watchlist(session, 'MyWatchlist')
15+
from tastytrade import PrivateWatchlist
16+
watchlist = PrivateWatchlist.get(session, 'MyWatchlist')
1917
print(watchlist.watchlist_entries)
2018
2119
>>> [{'symbol': 'AAPL', 'instrument-type': 'Equity'}, {'symbol': 'MSFT', 'instrument-type': 'Equity'}]
@@ -25,18 +23,26 @@ To add a symbol to the watchlist:
2523
.. code-block:: python
2624
2725
from tastytrade.instruments import InstrumentType
28-
Watchlist.add_symbol('SPY', InstrumentType.EQUITY)
29-
26+
watchlist.add_symbol('SPY', InstrumentType.EQUITY)
27+
3028
In this case, the symbol is present locally, but not remotely, so we need to update the remote list:
3129

3230
.. code-block:: python
3331
34-
watchlist.update_private_watchlist(session)
32+
watchlist.update(session)
3533
3634
We can also create a new watchlist from scratch, then publish it to the Tastytrade server:
3735

3836
.. code-block:: python
3937
40-
new_watchlist = Watchlist(name='NewWatchlist')
38+
new_watchlist = PrivateWatchlist(name='NewWatchlist')
4139
new_watchlist.add_symbol('USO', InstrumentType.EQUITY)
42-
new_watchlist.upload_private_watchlist(session)
40+
new_watchlist.upload(session)
41+
42+
You can also fetch public watchlists:
43+
44+
.. code-block:: python
45+
46+
from tastytrade import PublicWatchlist
47+
public_watchlist = PublicWatchlist.get(session, "Tom's Watchlist")
48+
print(public_watchlist.watchlist_entries)

0 commit comments

Comments
 (0)