Tastytrade Ruby SDK (Unofficial)

Gem Version CI Ruby Style Guide

An unofficial Ruby SDK for the Tastytrade API

⚠️ IMPORTANT DISCLAIMER: This is an unofficial SDK and is not affiliated with, endorsed by, or sponsored by Tastytrade, Tastyworks, or any of their affiliates. This is an independent project created to help Ruby developers interact with the Tastytrade API.

This Ruby gem provides a simple interface to interact with the Tastytrade API, allowing you to:

  • Authenticate with your Tastytrade account
  • Retrieve account information and balances
  • Access market data
  • Place and manage orders
  • Monitor positions and transactions

Features

  • Secure authentication with Tastytrade API
  • Real-time market data access
  • Account management and portfolio tracking
  • Order placement and management with dry-run support
  • Position monitoring
  • Transaction history with filtering and grouping
  • Buying power calculations and monitoring
  • CLI with interactive mode and rich formatting

Roadmap

See ROADMAP.md for the detailed development roadmap. Track progress on our GitHub Project Board.

Installation

Add this line to your application's Gemfile:

gem 'tastytrade'

And then execute:

bundle install

Or install it yourself as:

gem install tastytrade

Configuration

Environment Variables

The tastytrade gem supports authentication via environment variables, which is recommended for automation and CI/CD environments:

# Required for environment variable authentication
export TASTYTRADE_USERNAME="[email protected]"
export TASTYTRADE_PASSWORD="your_password"

# Optional environment variables
export TASTYTRADE_ENVIRONMENT="sandbox"  # Use "sandbox" for test environment
export TASTYTRADE_REMEMBER="true"        # Enable remember token

# Alternative shorter variable names
export TT_USERNAME="[email protected]"
export TT_PASSWORD="your_password"
export TT_ENVIRONMENT="sandbox"
export TT_REMEMBER="true"

When environment variables are set, the CLI will automatically use them for authentication without prompting for credentials.

Usage

Authentication

require 'tastytrade'

# Create a session
session = Tastytrade::Session.new(
  username: 'your_username',
  password: 'your_password',
  remember_me: true  # Optional: enables session refresh with remember token
)

# Login
session.

# Check if authenticated
session.authenticated? # => true

# Session will automatically refresh when expired if remember_me was enabled

CLI Usage

The gem includes a command-line interface for common operations:

Authentication

# Login to your account interactively
tastytrade login

# Login with remember option for automatic session refresh
tastytrade login --remember

# Login using environment variables (recommended for automation)
export TASTYTRADE_USERNAME="[email protected]"
export TASTYTRADE_PASSWORD="your_password"
tastytrade login

# Or use shorter variable names
export TT_USERNAME="[email protected]"
export TT_PASSWORD="your_password"
tastytrade login

# Use sandbox environment for testing
export TASTYTRADE_ENVIRONMENT="sandbox"
tastytrade login

# Enable remember token via environment
export TASTYTRADE_REMEMBER="true"
tastytrade login

Account Operations

# View account balances
tastytrade balance

# View balances for all accounts
tastytrade balance --all

# View account positions
tastytrade positions

# Filter positions by symbol
tastytrade positions --symbol AAPL

# Filter positions by underlying symbol (for options)
tastytrade positions --underlying-symbol SPY

# View trading status and permissions
tastytrade trading_status

# View status for specific account
tastytrade trading_status --account 5WT0001

# Include closed positions
tastytrade positions --include-closed

Transaction History

# View all transactions
tastytrade history

# Filter by date range
tastytrade history --start-date 2024-01-01 --end-date 2024-12-31

# Filter by symbol
tastytrade history --symbol AAPL

# Group transactions by symbol, type, or date
tastytrade history --group-by symbol
tastytrade history --group-by type
tastytrade history --group-by date

# Limit number of transactions
tastytrade history --limit 50

# Combine filters
tastytrade history --symbol AAPL --start-date 2024-01-01 --group-by date

Buying Power Status

# View buying power status
tastytrade buying_power

# View buying power for specific account
tastytrade buying_power --account 5WX12345

Order Management

Order Placement
# Place a limit buy order
tastytrade order place --symbol AAPL --action buy_to_open --quantity 100 --price 150.50

# Place a market order
tastytrade order place --symbol SPY --action buy_to_open --quantity 10 --type market

# Sell to close a position
tastytrade order place --symbol AAPL --action sell_to_close --quantity 100 --price 155.00

# Dry-run validation (validate without placing)
tastytrade order place --symbol MSFT --action buy_to_open --quantity 50 --price 300 --dry-run

# Skip confirmation prompt
tastytrade order place --symbol TSLA --action buy_to_open --quantity 10 --price 200 --skip-confirmation

# Supported actions:
# - buy_to_open (bto)
# - sell_to_close (stc) 
# - sell_to_open (sto)
# - buy_to_close (btc)

# Note: Orders that would use >80% of buying power will prompt for confirmation
Order Status and History
# List all live orders (open + last 24 hours)
tastytrade order list

# List orders with filters
tastytrade order list --status Live
tastytrade order list --symbol AAPL
tastytrade order list --all  # Show for all accounts

# Output orders in JSON format
tastytrade order list --format json

# Get historical orders (beyond 24 hours)
tastytrade order history
tastytrade order history --status Filled
tastytrade order history --symbol AAPL
tastytrade order history --from 2024-01-01 --to 2024-12-31
tastytrade order history --limit 100
tastytrade order history --format json

# Get details for a specific order
tastytrade order get ORDER_ID
tastytrade order get ORDER_ID --format json

# Cancel an order
tastytrade order cancel ORDER_ID
tastytrade order cancel ORDER_ID --account 5WX12345

# Replace/modify an order
tastytrade order replace ORDER_ID  # Interactive prompts for new price/quantity
tastytrade order replace ORDER_ID --price 155.00
tastytrade order replace ORDER_ID --quantity 50

Account Management

# List all accounts
tastytrade accounts

# Select an account
tastytrade select

# Check session status
tastytrade status

# Refresh session (requires remember token)
tastytrade refresh

# Logout
tastytrade logout

Account Information

# Get all accounts
accounts = Tastytrade::Models::Account.get_all(session)

# Get specific account
 = Tastytrade::Models::Account.get(session, 'account_number')

# Check account status
.closed? # => false
.futures_approved? # => true

Account Balances

# Get account balance
balance = .get_balances(session)

# Access balance information
balance.cash_balance # => BigDecimal("10000.50")
balance.net_liquidating_value # => BigDecimal("42001.00")
balance.equity_buying_power # => BigDecimal("20000.00")
balance.available_trading_funds # => BigDecimal("12000.00")
balance.day_trading_buying_power # => BigDecimal("40000.00")
balance.derivative_buying_power # => BigDecimal("20000.00")

# Check buying power usage
balance.buying_power_usage_percentage # => BigDecimal("40.00")
balance.derivative_buying_power_usage_percentage # => BigDecimal("25.00")
balance.high_buying_power_usage? # => false (checks if > 80%)

# Check if sufficient buying power for order
balance.sufficient_buying_power?(15000) # => true
balance.sufficient_buying_power?(15000, buying_power_type: :derivative) # => true

# Calculate buying power impact
balance.buying_power_impact_percentage(15000) # => BigDecimal("75.00")

# Calculate totals
balance.total_equity_value # => BigDecimal("30001.00")
balance.total_derivative_value # => BigDecimal("4500.00")
balance.total_market_value # => BigDecimal("34501.00")

Positions

# Get all positions
positions = .get_positions(session)

# Filter positions
positions = .get_positions(session, 
  symbol: 'AAPL',
  underlying_symbol: 'AAPL',
  include_closed: false
)

# Work with positions
positions.each do |position|
  puts position.symbol
  puts position.quantity
  puts position.unrealized_pnl
  puts position.unrealized_pnl_percentage

  # Check position type
  position.equity? # => true
  position.option? # => false
  position.long? # => true
  position.short? # => false
end

Order Placement

# Create an order leg for buying stock
leg = Tastytrade::OrderLeg.new(
  action: Tastytrade::OrderAction::BUY_TO_OPEN,
  symbol: 'AAPL',
  quantity: 100
)

# Create a market order
market_order = Tastytrade::Order.new(
  type: Tastytrade::OrderType::MARKET,
  legs: leg
)

# Create a limit order
limit_order = Tastytrade::Order.new(
  type: Tastytrade::OrderType::LIMIT,
  legs: leg,
  price: 150.50  # Will be converted to BigDecimal
)

# Place the order
response = .place_order(session, market_order)

# Dry run (simulate order without placing)
response = .place_order(session, limit_order, dry_run: true)

# Check order response
puts response.order_id           # => "123456"
puts response.status             # => "Filled"

# Dry run orders return a BuyingPowerEffect object
if response.buying_power_effect.is_a?(Tastytrade::Models::BuyingPowerEffect)
  bp_effect = response.buying_power_effect
  puts bp_effect.buying_power_change_amount # => BigDecimal("15050.00")
  puts bp_effect.buying_power_usage_percentage # => BigDecimal("75.25")
  puts bp_effect.exceeds_threshold?(80) # => false
  puts bp_effect.debit? # => true
else
  puts response.buying_power_effect # => BigDecimal("-15050.00")
end

puts response.warnings           # => [] or warning messages

Order Management

# Get live orders (open orders + orders from last 24 hours)
orders = .get_live_orders(session)

# Filter orders by status
live_orders = .get_live_orders(session, status: "Live")
filled_orders = .get_live_orders(session, status: "Filled")

# Filter orders by symbol
aapl_orders = .get_live_orders(session, underlying_symbol: "AAPL")

# Filter by time range
recent_orders = .get_live_orders(session,
  from_time: Time.now - 86400,  # Last 24 hours
  to_time: Time.now
)

# Work with order details
orders.each do |order|
  puts order.id                  # => "12345"
  puts order.status              # => "Live"
  puts order.underlying_symbol   # => "AAPL"
  puts order.order_type          # => "Limit"
  puts order.price               # => BigDecimal("150.50")

  # Check order capabilities
  puts order.cancellable?        # => true
  puts order.editable?           # => true
  puts order.terminal?           # => false
  puts order.working?            # => true

  # Check fill status
  puts order.remaining_quantity  # => 100
  puts order.filled_quantity     # => 0

  # Work with order legs
  order.legs.each do |leg|
    puts leg.symbol              # => "AAPL"
    puts leg.action              # => "Buy"
    puts leg.quantity            # => 100
    puts leg.remaining_quantity  # => 100
    puts leg.partially_filled?   # => false
  end
end

# Cancel an order
.cancel_order(session, "12345")

# Replace an order with new parameters
new_order = Tastytrade::Order.new(
  type: Tastytrade::OrderType::LIMIT,
  legs: leg,
  price: 155.00  # New price
)
response = .replace_order(session, "12345", new_order)

Order Validation

The SDK includes comprehensive order validation to prevent submission errors and ensure orders meet all requirements before reaching the API.

Validation Features

# Orders are automatically validated before submission
order = Tastytrade::Order.new(
  type: Tastytrade::OrderType::LIMIT,
  legs: leg,
  price: 150.00
)

# Validation happens automatically when placing orders
begin
  response = .place_order(session, order)
rescue Tastytrade::OrderValidationError => e
  puts "Validation failed:"
  e.errors.each { |error| puts "  - #{error}" }
end

# You can also validate manually
order.validate!(session, )  # Raises if invalid

# Or perform a dry-run validation
dry_run_response = order.dry_run(session, )
puts dry_run_response.buying_power_effect
puts dry_run_response.warnings

Validation Rules

The following validations are performed:

  1. Symbol Validation

    • Verifies symbol exists and is tradeable
    • Checks instrument type compatibility
  2. Quantity Validation

    • Minimum quantity: 1
    • Maximum quantity: 999,999
    • No fractional shares (whole numbers only)
  3. Price Validation

    • Price must be positive for limit orders
    • Price is rounded to appropriate tick size
    • Price reasonableness checks
  4. Account Permissions

    • Validates trading permissions for instrument type
    • Checks for account restrictions (frozen, closing-only, etc.)
    • Verifies options/futures permissions if applicable
  5. Buying Power Validation

    • Ensures sufficient buying power via dry-run
    • Warns if order uses >50% of available buying power
    • Checks margin requirements
  6. Market Hours Validation

    • Warns about market orders outside regular hours
    • Alerts for weekend submissions

Validation Errors

# Specific validation error types
Tastytrade::OrderValidationError     # General validation failure
Tastytrade::InvalidSymbolError       # Symbol doesn't exist
Tastytrade::InsufficientBuyingPowerError  # Not enough buying power
Tastytrade::AccountRestrictedError   # Account has restrictions
Tastytrade::InvalidQuantityError     # Quantity out of range
Tastytrade::InvalidPriceError        # Price validation failure
Tastytrade::MarketClosedError        # Market is closed

Using the OrderValidator

# Direct use of OrderValidator for custom validation
validator = Tastytrade::OrderValidator.new(session, , order)

# Perform full validation
validator.validate!  # Raises if invalid

# Or just dry-run validation
dry_run_response = validator.dry_run_validate!

# Check warnings and errors
puts validator.warnings  # Array of warning messages
puts validator.errors    # Array of error messages

Skip Validation (Use with Caution)

# Skip validation when you're certain the order is valid
response = .place_order(session, order, skip_validation: true)

Transaction History

# Get all transactions
transactions = .get_transactions(session)

# Filter transactions
transactions = .get_transactions(session,
  start_date: Date.new(2024, 1, 1),
  end_date: Date.new(2024, 12, 31),
  symbol: 'AAPL',
  transaction_types: ['Trade'],
  per_page: 100
)

# Work with transactions
transactions.each do |transaction|
  puts transaction.symbol               # => "AAPL"
  puts transaction.transaction_type     # => "Trade"
  puts transaction.transaction_sub_type # => "Buy"
  puts transaction.quantity             # => BigDecimal("100")
  puts transaction.price                # => BigDecimal("150.00")
  puts transaction.value                # => BigDecimal("-15000.00")
  puts transaction.net_value            # => BigDecimal("-15007.00")
  puts transaction.executed_at          # => Time object

  # Fee breakdown
  puts transaction.commission           # => BigDecimal("5.00")
  puts transaction.clearing_fees        # => BigDecimal("1.00")
  puts transaction.regulatory_fees      # => BigDecimal("0.50")
end

Development

After checking out the repo, run bin/setup to install dependencies and verify your environment is configured correctly.

Run tests with:

bundle exec rake spec

Run linting with:

bundle exec rake rubocop

For an interactive console:

bin/console

To install this gem onto your local machine:

bundle exec rake install

Documentation

TODO: Add links to additional documentation

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/ryanhamamura/tastytrade. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.

Please read CONTRIBUTING.md for details on our code of conduct and the process for submitting pull requests.

Security

Please see our security policy for reporting vulnerabilities.

License

The gem is available as open source under the terms of the MIT License.

Code of Conduct

Everyone interacting in the Tastytrade project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.

⚠️ IMPORTANT FINANCIAL DISCLAIMER

This software is provided for educational and informational purposes only. It is not intended to be used as financial advice, investment advice, or as a recommendation to buy, sell, or hold any securities or financial instruments.

TRADING RISKS: Trading securities, options, futures, and other financial instruments involves substantial risk of loss and is not suitable for all investors. Past performance is not indicative of future results. You may lose some or all of your invested capital.

NO WARRANTY: This software is provided "as is" without warranty of any kind, either express or implied, including but not limited to the implied warranties of merchantability, fitness for a particular purpose, or non-infringement.

YOUR RESPONSIBILITY: You are solely responsible for any investment and trading decisions you make using this software. You should consult with a qualified financial advisor before making any investment decisions.

API USAGE: By using this SDK, you are responsible for complying with Tastytrade's Terms of Service and API usage guidelines. Excessive API usage may result in rate limiting or account suspension by Tastytrade.

NOT AFFILIATED: This project is not affiliated with, endorsed by, or sponsored by Tastytrade, Tastyworks, or any of their affiliates. All trademarks and registered trademarks are the property of their respective owners.

The authors and contributors of this software shall not be held liable for any losses, damages, or costs of any kind arising from the use of this software.