schwaby is an unofficial Python client for the Charles Schwab API, built for running automated strategies against real accounts.
What is schwaby?
schwaby is an unofficial wrapper around the Charles Schwab Consumer APIs. It strives to be as thin and unopinionated as possible, offering an elegant programmatic interface over each endpoint. Notable functionality includes:
Login and authentication
Quotes, fundamentals, and historical pricing data
Options chains
Streaming quotes and order book depth data
Order construction, placement and management
Account info
Synchronous and asyncio clients over the same interface
How do I use schwaby?
For a full description of schwaby’s functionality, check out the documentation. Meanwhile, here’s a quick getting started guide:
Before you do anything, create an account and an application on the Charles Schwab developer site. You’ll receive an API key and app secret, which you can pass to this wrapper. You’ll also want to take note of your callback URI, as the login flow requires it. You app must be approved by Schwab before you can use it (this can take several days). You can find more detailed instructions here.
Next, install schwaby. Note the distribution is schwaby while the import stays schwab — pip install schwab-py fetches the original project, which is a different and much older codebase:
pip install "schwaby[login]"
[login] is there because the example below calls easy_client, which opens a browser login flow the first time it runs. Without it, the plain schwaby install is the three packages the library always needs. The interactive login flow and the order-code generator each need an extra — schwaby[login] and schwaby[codegen] — because neither is used by a program that loads its token from a file, and a bare install is twelve fewer packages on a machine that places trades. Calling either without its extra says so, and says what to install.
You’re good to go! To demonstrate, here’s how you can authenticate and fetch daily historical price data for the past twenty years:
from schwab import auth, client
import json
api_key = 'YOUR_API_KEY'
app_secret = 'YOUR_APP_SECRET'
callback_url = 'https://127.0.0.1:8182/'
token_path = '/path/to/token.json'
c = auth.easy_client(api_key, app_secret, callback_url, token_path)
r = c.get_price_history_every_day('AAPL')
r.raise_for_status()
print(json.dumps(r.json(), indent=4))
Why should I use schwaby?
Schwab’s API is capable, but several corners of it are tedious to get right and unforgiving when you get them wrong. schwaby takes on those corners and stays out of your way everywhere else:
Safe authentication. Schwab’s API supports OAuth authentication, but too many people online end up rolling their own implementation of the OAuth callback flow. This is both unnecessarily complex and dangerous. schwaby handles token fetch and refreshing for you.
A usable streaming client. Schwab’s streamer is a raw websocket that identifies every field by number, and the same number means different things on different services — field 2 is the ask price on LEVELONE_EQUITIES and the open price on CHART_EQUITY. schwaby carries the field tables for all thirteen services and relabels each message as it arrives, so you receive {'ASK_PRICE': 421.6, ...} rather than {'2': 421.6, ...}. It also handles login and logout, keeps track of which response belongs to which request, and lets you register a handler per service rather than demultiplexing the stream yourself.
Order construction Schwab will accept. Order JSON is deeply nested, and a malformed order comes back rejected with little explanation of what was wrong. OrderBuilder assembles it from named parts and validates the values it can, and schwab.orders.equities and schwab.orders.options provide ready-made templates for the common equity orders and option strategies. schwab.contrib.orders runs the process backwards: hand it an order you have already placed and it returns the builder that would place it again.
Enums rather than magic strings. Each endpoint’s legal parameter values are enums on the client, so a misspelled projection or an invalid order duration fails immediately in Python instead of arriving as an opaque HTTP 400 in the middle of a session.
Minimal wrapping everywhere else. Unlike some other API wrappers, which build in lots of logic and validation, schwaby takes raw values and returns the raw httpx2 response, allowing you to interpret the complex API responses as you see fit. Anything you can do with raw HTTP requests you can do with schwaby, only more easily.
The documentation linked above is worth reading even if you end up calling the API directly. Schwab’s own developer portal is behind a login, so for a good deal of this API those pages are the most accessible description of how it actually behaves.
Why should I not use schwaby?
As excellent as Schwab’s API is, there are a few popular features it does not offer:
While Charles Schwab owns thinkorswim (AKA TOS), this API is unaffiliated with it. You can access and trade against the same accounts as TOS, but some of TOS’s functionality is not supported by schwaby
Paper trading is not supported
Historical options pricing data is not available.
What else?
Bug reports, suggestions, and patches are welcome. Submit issues here and pull requests here.
If the problem is with behaviour this project shares with alexgolec/schwab-py and is not one of the changes listed in the changelog, it is worth reporting there too — it will help more people than a report here alone.
schwaby is released under the MIT license, and remains copyright Alex Golec.
Disclaimer: schwaby is an unofficial API wrapper. It is in no way endorsed by or affiliated with Charles Schwab or any associated organization. Make sure to read and understand the terms of service of the underlying API before using this package. This authors accept no responsibility for any damage that might stem from use of this package. See the LICENSE file for more details.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file schwaby-2.6.0.tar.gz.
File metadata
- Download URL: schwaby-2.6.0.tar.gz
- Upload date:
- Size: 187.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e1d764ad40d6a28cf8e82ab03426253d9d053339f8cc84a9b2b578d72b1fdc68
|
|
| MD5 |
349b068d1b98d7e483f57810933ddc0b
|
|
| BLAKE2b-256 |
c6eb747f51174413992019b362249c454795d78e716ac97ef25f8fc5b7ef74bd
|
Provenance
The following attestation bundles were made for schwaby-2.6.0.tar.gz:
Publisher:
publish.yml on Hu1kSmash/schwaby
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
schwaby-2.6.0.tar.gz -
Subject digest:
e1d764ad40d6a28cf8e82ab03426253d9d053339f8cc84a9b2b578d72b1fdc68 - Sigstore transparency entry: 2728679007
- Sigstore integration time:
-
Permalink:
Hu1kSmash/schwaby@5861ff159d518b34bd50d245a3456f320be60ba6 -
Branch / Tag:
refs/tags/v2.6.0 - Owner: https://github.com/Hu1kSmash
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5861ff159d518b34bd50d245a3456f320be60ba6 -
Trigger Event:
release
-
Statement type:
File details
Details for the file schwaby-2.6.0-py3-none-any.whl.
File metadata
- Download URL: schwaby-2.6.0-py3-none-any.whl
- Upload date:
- Size: 195.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f1f4dcd0d0eb2b046c8681b0dcaccab6499cac5105874ce4e3511f5e7d47705d
|
|
| MD5 |
a23db552d0d511f9392dbb570f8aca7f
|
|
| BLAKE2b-256 |
24d16f638abb19a8561d421cde0d8e26ec1bfc373db3227c23a0c31e60f60722
|
Provenance
The following attestation bundles were made for schwaby-2.6.0-py3-none-any.whl:
Publisher:
publish.yml on Hu1kSmash/schwaby
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
schwaby-2.6.0-py3-none-any.whl -
Subject digest:
f1f4dcd0d0eb2b046c8681b0dcaccab6499cac5105874ce4e3511f5e7d47705d - Sigstore transparency entry: 2728679588
- Sigstore integration time:
-
Permalink:
Hu1kSmash/schwaby@5861ff159d518b34bd50d245a3456f320be60ba6 -
Branch / Tag:
refs/tags/v2.6.0 - Owner: https://github.com/Hu1kSmash
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@5861ff159d518b34bd50d245a3456f320be60ba6 -
Trigger Event:
release
-
Statement type: