This code is vibe-coded slop. It may be useful if you're trying to implement your own API calls to Public.
Some problems I encountered with this code:
- The AI made some really dangerous decisions on how it was canceling orders—potentially increasing the size of trades way higher than intended. I think I fixed this, but I can't be sure there aren't more problems.
- The Public API seems to have some issues with concurrency. This code attempts to solve this problem by only sending one account state modification API call at a time.
- I was simply blasting APIs, and an order got stuck such that I could not close it. The order went away at the end of the day (as it was supposed to), but the Public support folks could not cancel the order for me and have not given me a reason why it happened.
This is a personal project—and not meant to be used by general folks or to solve problems in general for all uses. Unfortunately I don't have time to maintain this code for everyone. Feel free to fork this project.
A comprehensive Python trading system with an interactive shell interface for the Public Brokerage API. Features walk limit orders, sophisticated spread trading, and advanced position management.
- Complete API Coverage: All 16 Public API endpoints supported
- Type Safety: Full Pydantic models for request/response validation
- Authentication Management: Automatic access token handling and refresh
- Error Handling: Comprehensive error handling with retries
- Rate Limiting: Built-in retry logic for rate-limited requests
- Logging: Configurable debug logging
- Context Manager: Clean resource management
Clone the repository and install dependencies:
git clone https://github.com/yourusername/public-brokerage.git
cd public-brokerage
pip install -e .public-brokerage/
├── public_brokerage/ # Main library package
│ ├── models/ # Data models and schemas
│ ├── accounts.py # Account management
│ ├── orders.py # Order operations
│ ├── positions.py # Position tracking
│ └── client.py # HTTP client
├── shell.py # Interactive trading shell
├── walk_limit_engine.py # Automated order management
├── *_test.py # Unit tests (follow naming convention)
└── README.md # This file
## Quick Start
### 1. Set up your environment
Create a `.env` file (copy from `.env.example`):
```bash
cp .env.example .env
Edit .env and add your Personal Secret Token from your Public account settings:
PUBLIC_SECRET_TOKEN=your_secret_token_here
import os
from dotenv import load_dotenv
from public_brokerage.client import PublicBrokerageClient
from public_brokerage.auth import create_access_token
from public_brokerage.accounts import get_accounts
# Load environment variables
load_dotenv()
# Create client
client = PublicBrokerageClient(
secret_token=os.getenv("PUBLIC_SECRET_TOKEN"),
debug=True # Enable debug logging
)
# Create access token
access_token = create_access_token(client=client)
print(f"Access token: {access_token}")
# Get accounts
accounts = get_accounts(client)
print(f"Found {len(accounts)} accounts")
# Close client when done
client.close()from public_brokerage.client import PublicBrokerageClient
from public_brokerage.accounts import get_accounts, get_account_portfolio
# Use context manager for automatic cleanup
with PublicBrokerageClient(secret_token="your_token") as client:
# Get accounts
accounts = get_accounts(client)
# Get portfolio for first account
if accounts:
portfolio = get_account_portfolio(client, accounts[0].accountId)
print(f"Account {accounts[0].accountId} has {len(portfolio.positions)} positions")from public_brokerage.auth import create_access_token
# Create access token (15 minute validity by default)
token = create_access_token(secret="your_secret", validity_minutes=15)
# Or let it read from environment
token = create_access_token() # Uses PUBLIC_SECRET_TOKEN env varfrom public_brokerage.accounts import get_accounts, get_account_portfolio, get_account_history
from datetime import datetime
# Get all accounts
accounts = get_accounts(client)
# Get portfolio for an account
portfolio = get_account_portfolio(client, account_id)
# Get account history with optional filters
history = get_account_history(
client,
account_id,
start=datetime(2024, 1, 1),
end=datetime(2024, 12, 31),
page_size=100
)from public_brokerage.instruments import get_all_instruments, get_instrument
# Get all instruments
instruments = get_all_instruments(client)
# Get specific instrument
instrument = get_instrument(client, "AAPL", "EQUITY")from public_brokerage.market_data import get_quotes, get_option_chain, get_option_greeks
from public_brokerage.models.common import Instrument, InstrumentType
from datetime import date
# Get quotes
instruments = [Instrument(symbol="AAPL", type=InstrumentType.EQUITY)]
quotes = get_quotes(client, account_id, instruments)
# Get option chain
underlying = Instrument(symbol="AAPL", type=InstrumentType.EQUITY)
option_chain = get_option_chain(client, account_id, underlying, date(2024, 1, 19))
# Get option Greeks
greeks = get_option_greeks(client, account_id, "AAPL 240119C00150000")from public_brokerage.orders import place_order, get_order, cancel_order, preflight_single_leg
from public_brokerage.models.order import OrderRequest
from public_brokerage.models.common import Instrument, InstrumentType, OrderSide, OrderType, Expiration, TimeInForce
import uuid
# Create order request
order_request = OrderRequest(
orderId=str(uuid.uuid4()),
instrument=Instrument(symbol="AAPL", type=InstrumentType.EQUITY),
orderSide=OrderSide.BUY,
orderType=OrderType.MARKET,
expiration=Expiration(timeInForce=TimeInForce.DAY),
quantity="1"
)
# Preflight the order (get cost estimates)
preflight = preflight_single_leg(client, account_id, order_request)
print(f"Estimated cost: ${preflight.estimatedCost}")
# Place the order
order_id = place_order(client, account_id, order_request)
print(f"Order placed: {order_id}")
# Check order status
order = get_order(client, account_id, order_id)
print(f"Order status: {order.status}")
# Cancel order if needed
cancel_order(client, account_id, order_id)The library includes an interactive shell interface for easy trading operations:
# Interactive mode - enter commands interactively
python shell.py
# Batch mode - pipe commands to shell
echo -e "accounts\npositions 12345678\nexit" | python shell.pyaccounts- List all your accountspositions [account_id]- Show positions for an accountoptions <symbol>- Show option expirations for symbolchain <symbol> <expiration>- Show option chainquote <symbol>- Get real-time quoteopen_call_spread- Open call spread with walk limit ordersclose_call_spread- Close call spreads with walk limit ordersstatus- Show all background process statuscancel <process_id>- Cancel a specific process and its ordercancel all- Cancel ALL active processes and their broker orderslogs <process_id>- Show process execution logshelp- Show all available commandsexit- Exit the shell
Use the walk limit engine to automatically manage partial fills and cancellations:
# In the shell
walk_limit 12345678 my_order.jsonExample order JSON file:
{
"orderId": "unique-order-id",
"instrument": {"symbol": "SPY", "type": "EQUITY"},
"orderSide": "BUY",
"orderType": "LIMIT",
"expiration": {"timeInForce": "DAY"},
"quantity": "10",
"limitPrice": "420.50"
}The walk limit engine will:
- Monitor for partial fills
- Automatically handle remaining quantities
- Provide real-time status updates
- Cancel unfilled portions when needed
cancel all command will immediately cancel ALL active orders with your broker, not just stop the background processes. Use with extreme caution in live trading!
- Interactive Mode: Full command history and auto-completion
- Batch Mode: Execute multiple commands with
-eflag - Status Updates: Real-time progress for long-running operations
- Error Handling: Graceful error messages and recovery
- Position Tracking: Monitor account positions and balances
The library uses standard Python exceptions:
import requests
from public_brokerage import PublicBrokerageClient
from public_brokerage.accounts import get_accounts
try:
with PublicBrokerageClient(secret_token="invalid") as client:
accounts = get_accounts(client)
except requests.exceptions.HTTPError as e:
print(f"HTTP error: {e}")
except ValueError as e:
print(f"Validation error: {e}")
except Exception as e:
print(f"Unexpected error: {e}")PUBLIC_SECRET_TOKEN: Your Personal Secret Token (required)ACCESS_TOKEN_VALIDITY_MINUTES: Default token validity (default: 15)PUBLIC_API_BASE_URL: API base URL (default: https://public.com)REQUEST_TIMEOUT: Request timeout in seconds (default: 30)MAX_RETRIES: Maximum retry attempts (default: 3)DEBUG_LOGGING: Enable debug logging (default: False)
client = PublicBrokerageClient(
secret_token="your_token",
base_url="https://public.com",
timeout=30,
max_retries=3,
debug=True
)Run the unit tests:
python -m unittest discover . -p "*_test.py"Run specific test modules:
python -m unittest client_test
python -m unittest auth_test
python -m unittest walk_limit_engine_testRun with coverage:
pip install coverage
coverage run -m unittest discover . -p "*_test.py"
coverage report
coverage html # Generate HTML report- Fork the repository
- Create a feature branch
- Add tests for your changes
- Ensure all tests pass
- Submit a pull request
The Public Individual API is for personal, non-commercial use only. See Public's API terms for details.
MIT License - see LICENSE file for details.
- Documentation: Public API Docs
- Issues: GitHub Issues
- Email: API Support