Skip to main content

Python SDK for Public.com API

Project description

Public API Python SDK

Version Python License

Public API Python SDK

A Python SDK for interacting with the Public Trading API, providing a simple and intuitive interface for trading operations, market data retrieval, and account management.

Installation

From PyPI

$ pip install publicdotcom-py

Run locally

$ python3 -m venv .venv
$ source .venv/bin/activate
$ pip install .

$ pip install -e .
$ pip install -e ".[dev]"  # for dev dependencies

$ # run example
$ python example.py

Run tests

$ pytest

Run examples

Inside of the examples folder are multiple python scripts showcasing specific ways to use the SDK. To run these Python files, first add your API_SECRET_KEY and DEFAULT_ACCOUNT_NUMBER to the .env.example file and change the filename to .env.

Quick Start

from public_api_sdk import PublicApiClient, PublicApiClientConfiguration
from public_api_sdk.auth_config import ApiKeyAuthConfig

# Initialize the client
client = PublicApiClient(
    ApiKeyAuthConfig(api_secret_key="INSERT_API_SECRET_KEY"),
    config=PublicApiClientConfiguration(
        default_account_number="INSERT_ACCOUNT_NUMBER"
    )
)

# Get accounts
accounts = client.get_accounts()

# Get a quote
from public_api_sdk import OrderInstrument, InstrumentType

quotes = client.get_quotes([
    OrderInstrument(symbol="AAPL", type=InstrumentType.EQUITY)
])

API Reference

Client Configuration

The PublicApiClient is initialized with an API secret key create in your settings page at public.com and optional configuration. The SDK client will handle generation and refresh of access tokens:

from public_api_sdk import PublicApiClient, PublicApiClientConfiguration
from public_api_sdk.auth_config import ApiKeyAuthConfig

config = PublicApiClientConfiguration(
    default_account_number="INSERT_ACCOUNT_NUMBER",  # Optional default account
)

client = PublicApiClient(
        ApiKeyAuthConfig(api_secret_key="INSERT_API_SECRET_KEY"),
        config=config
    )

Default Account Number

The default_account_number configuration option simplifies API calls by eliminating the need to specify account_id in every method call. When set, any method that accepts an optional account_id parameter will automatically use the default account number if no account ID is explicitly provided.

# With default_account_number configured
from public_api_sdk import OrderInstrument, InstrumentType

config = PublicApiClientConfiguration(
    default_account_number="INSERT_ACCOUNT_NUMBER"
)

client = PublicApiClient(
        ApiKeyAuthConfig(api_secret_key="INSERT_API_SECRET_KEY"), 
        config=config
    )

instruments = [
    OrderInstrument(symbol="AAPL", type=InstrumentType.EQUITY),
    OrderInstrument(symbol="MSFT", type=InstrumentType.EQUITY)
]

# No need to specify account_id
portfolio = client.get_portfolio()  # Uses default account number
quotes = client.get_quotes(instruments)   # Uses default account number

# You can still override with a specific account
other_portfolio = client.get_portfolio(account_id="DIFFERENT123")  # Uses "DIFFERENT123"
# Without default_account_number
config = PublicApiClientConfiguration()

client = PublicApiClient(
        ApiKeyAuthConfig(api_secret_key="INSERT_API_SECRET_KEY"), 
        config=config
    )

# Must specify account_id for each call
portfolio = client.get_portfolio(account_id="INSERT_ACCOUNT_NUMBER")  # Required
quotes = client.get_quotes(instruments, account_id="INSERT_ACCOUNT_NUMBER")  # Required

This is particularly useful when working with a single account, as it reduces code repetition and makes the API calls cleaner.

Account Management

Get Accounts

Retrieve all accounts associated with the authenticated user.

accounts_response = client.get_accounts()
for account in accounts_response.accounts:
    print(f"Account ID: {account.account_id}, Type: {account.account_type}")

Get Portfolio

Get a snapshot of account portfolio including positions, equity, and buying power.

portfolio = client.get_portfolio(account_id="YOUR_ACCOUNT_NUMBER")  # account_id optional if default set
print(f"Total equity: {portfolio.equity}")
print(f"Buying power: {portfolio.buying_power}")

Get Account History

Retrieve paginated account history with optional filtering.

from public_api_sdk import HistoryRequest

history = client.get_history(
    HistoryRequest(page_size=10),
    account_id="YOUR_ACCOUNT"
)

Market Data

Get Quotes

Retrieve real-time quotes for multiple instruments.

from public_api_sdk import OrderInstrument, InstrumentType

quotes = client.get_quotes([
    OrderInstrument(symbol="AAPL", type=InstrumentType.EQUITY),
    OrderInstrument(symbol="GOOGL", type=InstrumentType.EQUITY)
])

for quote in quotes:
    print(f"{quote.instrument.symbol}: ${quote.last}")

Get Instrument Details

Get detailed information about a specific instrument.

instrument = client.get_instrument(
    symbol="AAPL",
    instrument_type=InstrumentType.EQUITY
)

print(f"Symbol: {instrument.instrument.symbol}")
print(f"Type: {instrument.instrument.type}")
print(f"Trading: {instrument.trading}")
print(f"Fractional Trading: {instrument.fractional_trading}")
print(f"Option Trading: {instrument.option_trading}")
print(f"Option Spread Trading: {instrument.option_spread_trading}")

Get All Instruments

Retrieve all available trading instruments with optional filtering.

from public_api_sdk import InstrumentsRequest, InstrumentType, Trading

instruments = client.get_all_instruments(
    InstrumentsRequest(
        type_filter=[InstrumentType.EQUITY],
        trading_filter=[Trading.BUY_AND_SELL],
    )
)

Options Trading

Get Option Expirations

Retrieve available option expiration dates for an underlying instrument.

from public_api_sdk import OptionExpirationsRequest, OrderInstrument, InstrumentType

expirations = client.get_option_expirations(
    OptionExpirationsRequest(
        instrument=OrderInstrument(
            symbol="AAPL", 
            type=InstrumentType.EQUITY
        )
    )
)
print(f"Available expirations: {expirations.expirations}")

Get Option Chain

Retrieve the option chain for a specific expiration date.

from public_api_sdk import OptionChainRequest, InstrumentType

option_chain = client.get_option_chain(
    OptionChainRequest(
        instrument=OrderInstrument(symbol="AAPL", type=InstrumentType.EQUITY),
        expiration_date=expirations.expirations[0]
    )
)

Get Option Greeks

Get Greeks for a single option contract (OSI format).

greeks = client.get_option_greek(
    osi_symbol="AAPL260116C00270000"
)
print(f"Delta: {greeks.greeks.delta}, Gamma: {greeks.greeks.gamma}")

For multiple option symbols, use get_option_greeks (plural):

greeks_response = client.get_option_greeks(
    osi_symbols=["AAPL260116C00270000", "AAPL260116P00270000"]
)
for greek in greeks_response.greeks:
    print(f"Delta: {greek.greeks.delta}, Gamma: {greek.greeks.gamma}")

Order Management

Market Session Selection

When placing equity orders, you can optionally specify the market session using the equity_market_session parameter:

  • EquityMarketSession.CORE - Trade during regular market hours (9:30 AM - 4:00 PM ET)
  • EquityMarketSession.EXTENDED - Trade during pre-market (4:00 AM - 9:30 AM ET) and after-hours (4:00 PM - 8:00 PM ET)
from public_api_sdk import EquityMarketSession

# For regular market hours
equity_market_session=EquityMarketSession.CORE

# For extended hours trading
equity_market_session=EquityMarketSession.EXTENDED

This parameter is optional and applies to both preflight calculations and order placement for equity instruments.

Preflight Calculations

Equity Preflight

Calculate estimated costs and impact before placing an equity order.

from public_api_sdk import PreflightRequest, OrderSide, OrderType, TimeInForce, OrderInstrument, InstrumentType
from public_api_sdk import OrderExpirationRequest, EquityMarketSession
from decimal import Decimal

preflight_request = PreflightRequest(
    instrument=OrderInstrument(symbol="AAPL", type=InstrumentType.EQUITY),
    order_side=OrderSide.BUY,
    order_type=OrderType.LIMIT,
    expiration=OrderExpirationRequest(time_in_force=TimeInForce.DAY),
    quantity=10,
    limit_price=Decimal("227.50"),
    equity_market_session=EquityMarketSession.CORE  # Optional: CORE or EXTENDED
)

preflight_response = client.perform_preflight_calculation(preflight_request)
print(f"Estimated commission: ${preflight_response.estimated_commission}")
print(f"Order value: ${preflight_response.order_value}")
Multi-Leg Preflight

Calculate estimated costs for complex multi-leg option strategies.

preflight_multi = PreflightMultiLegRequest(
    order_type=OrderType.LIMIT,
    expiration=OrderExpirationRequest(
        time_in_force=TimeInForce.GTD,
        expiration_time=datetime(2025, 12, 1, tzinfo=timezone.utc)
    ),
    quantity=1,
    limit_price=Decimal("3.45"),
    legs=[
        OrderLegRequest(
            instrument=LegInstrument(symbol="AAPL251024C00110000", type=LegInstrumentType.OPTION),
            side=OrderSide.SELL,
            open_close_indicator=OpenCloseIndicator.OPEN,
            ratio_quantity=1
        ),
        OrderLegRequest(
            instrument=LegInstrument(symbol="AAPL251024C00120000", type=LegInstrumentType.OPTION),
            side=OrderSide.BUY,
            open_close_indicator=OpenCloseIndicator.OPEN,
            ratio_quantity=1
        )
    ]
)

# Calculate preflight to get strategy details and costs
preflight_result = client.perform_multi_leg_preflight_calculation(preflight_multi)

# Display results
print("\n" + "="*70)
print(f"Strategy: {preflight_result.strategy_name}")
print("="*70)

print(f"\nOrder Details:")
print(f"  Order Type: {preflight_multi.order_type.value}")
print(f"  Quantity: {preflight_multi.quantity}")
print(f"  Limit Price: ${preflight_multi.limit_price}")

print(f"\nLegs:")
for i, leg in enumerate(preflight_multi.legs, 1):
    print(f"  {i}. {leg.side.value} {leg.instrument.symbol}")

cost = float(preflight_result.estimated_cost)
cost_label = "Debit (Cost)" if cost > 0 else "Credit"
print(f"\nCost Analysis:")
print(f"  {cost_label}: ${abs(cost):.2f}")
print(f"  Commission: ${preflight_result.estimated_commission}")
print(f"  Buying Power Required: ${preflight_result.buying_power_requirement}")

print("\n" + "="*70)

Place Orders

Place Single-Leg Order

Submit a single-leg equity or option order.

from public_api_sdk import OrderRequest, OrderInstrument, InstrumentType, EquityMarketSession
import uuid

order_request = OrderRequest(
    order_id=str(uuid.uuid4()),
    instrument=OrderInstrument(symbol="AAPL", type=InstrumentType.EQUITY),
    order_side=OrderSide.BUY,
    order_type=OrderType.LIMIT,
    expiration=OrderExpirationRequest(time_in_force=TimeInForce.DAY),
    quantity=10,
    limit_price=Decimal("227.50"),
    equity_market_session=EquityMarketSession.EXTENDED  # Optional: CORE or EXTENDED
)

order_response = client.place_order(order_request)
print(f"Order placed with ID: {order_response.order_id}")
Place Multi-Leg Order

Submit a multi-leg option strategy order.

from datetime import datetime, timezone
from public_api_sdk import MultilegOrderRequest
import uuid

multileg_order = MultilegOrderRequest(
    order_id=str(uuid.uuid4()),
    quantity=1,
    type=OrderType.LIMIT,
    limit_price=Decimal("3.45"),
    expiration=OrderExpirationRequest(
        time_in_force=TimeInForce.GTD,
        expiration_time=datetime(2025, 10, 31, tzinfo=timezone.utc)
    ),
    legs=[
        OrderLegRequest(
            instrument=LegInstrument(
                symbol="AAPL251024C00110000",
                type=LegInstrumentType.OPTION
            ),
            side=OrderSide.SELL,
            open_close_indicator=OpenCloseIndicator.OPEN,
            ratio_quantity=1
        ),
        OrderLegRequest(
            instrument=LegInstrument(
                symbol="AAPL251024C00120000",
                type=LegInstrumentType.OPTION
            ),
            side=OrderSide.BUY,
            open_close_indicator=OpenCloseIndicator.OPEN,
            ratio_quantity=1
        )
    ]
)

multileg_response = client.place_multileg_order(multileg_order)
print(f"Multi-leg order placed: {multileg_response.order_id}")

Get Order Status

Retrieve the status and details of a specific order.

order_details = client.get_order(
    order_id="YOUR_ORDER_ID",
    account_id="YOUR_ACCOUNT"  # optional if default set
)
print(f"Order status: {order_details.status}")

Cancel Order

Submit an asynchronous request to cancel an order.

client.cancel_order(
    order_id="YOUR_ORDER_ID",
    account_id="YOUR_ACCOUNT"  # optional if default set
)
# Note: Check order status after to confirm cancellation

Price Subscription

Basic Usage

from public_api_sdk import (
    PublicApiClient,
    PublicApiClientConfiguration,
    OrderInstrument,
    InstrumentType,
    PriceChange,
    SubscriptionConfig,
)

# initialize client
config = PublicApiClientConfiguration(
    default_account_number="YOUR_ACCOUNT"
)
client = PublicApiClient(
    api_secret_key="YOUR_KEY",
    config=config
)

# define callback
def on_price_change(price_change: PriceChange):
    print(f"{price_change.instrument.symbol}: "
          f"{price_change.old_quote.last} -> {price_change.new_quote.last}")

instruments = [
    OrderInstrument(symbol="AAPL", type=InstrumentType.EQUITY),
    OrderInstrument(symbol="GOOGL", type=InstrumentType.EQUITY),
]

subscription_id = client.subscribe_to_price_changes(
    instruments=instruments,
    callback=on_price_change,
    config=SubscriptionConfig(polling_frequency_seconds=2.0)
)

# ...

# unsubscribe
client.unsubscribe(subscription_id)

Async Callbacks

async def async_price_handler(price_change: PriceChange):
    # Async processing
    await process_price_change(price_change)

client.subscribe_to_price_changes(
    instruments=instruments,
    callback=async_price_handler  # Async callbacks are automatically detected
)

Subscription Management

# update polling frequency
client.set_polling_frequency(subscription_id, 5.0)

# get all active subscriptions
active = client.get_active_subscriptions()

# unsubscribe all
client.unsubscribe_all()

Custom Configuration

config = SubscriptionConfig(
    polling_frequency_seconds=1.0,  # poll every second
    retry_on_error=True,            # retry on API errors
    max_retries=5,                  # maximum retry attempts
    exponential_backoff=True        # use exponential backoff for retries
)

subscription_id = client.subscribe_to_price_changes(
    instruments=instruments,
    callback=on_price_change,
    config=config
)

Examples

Complete Trading Workflow

See example.py for a complete trading workflow example that demonstrates:

  • Getting accounts
  • Retrieving quotes
  • Performing preflight calculations
  • Placing orders
  • Checking order status
  • Getting portfolio information
  • Retrieving account history

Options Trading Example

See example_options.py for a comprehensive options trading example that shows:

  • Getting option expirations
  • Retrieving option chains
  • Getting option Greeks
  • Performing multi-leg preflight calculations
  • Placing multi-leg option orders

Price Subscription

See example_price_subscription.py for complete examples including:

  • Basic subscription usage
  • Advanced async callbacks
  • Multiple concurrent subscriptions
  • Custom price alert system

Error Handling

The SDK will raise exceptions for API errors. It's recommended to wrap API calls in try-except blocks:

try:
    order_response = client.place_order(order_request)
except Exception as e:
    print(f"Error placing order: {e}")
finally:
    client.close()

Important Notes

  • Order placement is asynchronous. Always use get_order() to verify order status.
  • For accounts with a default account number configured, the account_id parameter is optional in most methods.
  • The client manages token refresh automatically.
  • Always call client.close() when done to clean up resources.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

publicdotcom_py-0.1.7.tar.gz (58.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

publicdotcom_py-0.1.7-py3-none-any.whl (48.2 kB view details)

Uploaded Python 3

File details

Details for the file publicdotcom_py-0.1.7.tar.gz.

File metadata

  • Download URL: publicdotcom_py-0.1.7.tar.gz
  • Upload date:
  • Size: 58.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for publicdotcom_py-0.1.7.tar.gz
Algorithm Hash digest
SHA256 8d07764f666affbf49797f58d44c7fe4501f52d3a4789a78ad667d1c2b203fe7
MD5 0cc5eea6884b10d7081c0c70d9b0b0fc
BLAKE2b-256 dff27e4d500852406c0c2cd9a167f161452561eb4b4c991c367be69b4c56fc73

See more details on using hashes here.

File details

Details for the file publicdotcom_py-0.1.7-py3-none-any.whl.

File metadata

File hashes

Hashes for publicdotcom_py-0.1.7-py3-none-any.whl
Algorithm Hash digest
SHA256 4608ef922f64dc8ee3c6d6291747f2624e97f6e8279d53c1e4122081f6b85d4c
MD5 1ae03cd8f99a025812482afdaa9a83df
BLAKE2b-256 b36d8bc5eb8904061fb628621eff7d3de595e945c05888cac4639ab28c1aef82

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page