schwab 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 66555bd3340fd44588d10ba42d2ae9814ee1407726cdff5af8264f10675adb78
4
+ data.tar.gz: ed38e6126aba0a04c8e91eef320c74efff55b3a55113d1755b0b80d7b623fb82
5
+ SHA512:
6
+ metadata.gz: 3f4ac7b6a471921e15e0dd928ce64593a12186a4af9a7492536385640ca9064b3f1bfc88cc2ca4189fdf3de3c9c041479bbe662cdfa06f2a268adf3d842791d1
7
+ data.tar.gz: 56350f5b1cee338a971015eae51fe4710739033849a2c90a557d1a5f26db929e4ff70365e8c8dabc338496537e716e79c2b650de5fd664d137ddac93413ba6eb
data/.brakeman.yml ADDED
@@ -0,0 +1,75 @@
1
+ # Brakeman configuration for Schwab SDK
2
+ # This is a Ruby gem/library, not a Rails application
3
+
4
+ # Skip Rails-specific checks since this is a gem
5
+ skip_checks:
6
+ - CheckBasicAuth
7
+ - CheckCrossSiteScripting
8
+ - CheckDefaultRoutes
9
+ - CheckDetailedExceptions
10
+ - CheckDigestDoS
11
+ - CheckExecute
12
+ - CheckFileAccess
13
+ - CheckFilterSkipping
14
+ - CheckForgerySetting
15
+ - CheckJSONEncoding
16
+ - CheckJSONParsing
17
+ - CheckMailTo
18
+ - CheckMassAssignment
19
+ - CheckModelAttrAccessible
20
+ - CheckModelAttributes
21
+ - CheckModelSerialize
22
+ - CheckNestedAttributes
23
+ - CheckQuoteTableName
24
+ - CheckRedirect
25
+ - CheckRender
26
+ - CheckRenderDoS
27
+ - CheckResponseSplitting
28
+ - CheckRouteDoS
29
+ - CheckSafeBufferManipulation
30
+ - CheckSelectTag
31
+ - CheckSelectVulnerability
32
+ - CheckSend
33
+ - CheckSendFile
34
+ - CheckSessionSettings
35
+ - CheckSingleQuotes
36
+ - CheckSkipBeforeFilter
37
+ - CheckSQL
38
+ - CheckSSLVerify
39
+ - CheckStripTags
40
+ - CheckSymbolDoSCVE
41
+ - CheckTranslateBug
42
+ - CheckUnsafeReflection
43
+ - CheckValidationRegex
44
+ - CheckWithoutProtection
45
+ - CheckXMLDoS
46
+
47
+ # Scan these directories
48
+ app_path: lib
49
+
50
+ # Ignore these files/directories
51
+ skip_files:
52
+ - spec/
53
+ - test/
54
+ - doc/
55
+ - coverage/
56
+ - bin/oauth_test.rb # Interactive script with user input
57
+
58
+ # Don't assume this is a Rails app
59
+ rails3: false
60
+ rails4: false
61
+ rails5: false
62
+ rails6: false
63
+ rails7: false
64
+ assume_all_routes: false
65
+
66
+ # Output settings
67
+ report_direct: false
68
+ summary_only: false
69
+
70
+ # Security settings
71
+ run_all_checks: false
72
+ interprocedural: false
73
+
74
+ # Confidence level (1 = High, 2 = Medium, 3 = Weak)
75
+ confidence_level: 2
@@ -0,0 +1,120 @@
1
+ # release-pr
2
+
3
+ Create a release PR following Ruby gem best practices.
4
+
5
+ ## Steps to Execute
6
+
7
+ 1. **Determine Version Bump**
8
+ - Review the CHANGELOG.md "Unreleased" section
9
+ - Determine the appropriate version bump based on Semantic Versioning:
10
+ - MAJOR (x.0.0): Breaking changes
11
+ - MINOR (0.x.0): New features, backward compatible
12
+ - PATCH (0.0.x): Bug fixes only
13
+ - Ask the user to confirm the version if unclear
14
+
15
+ 2. **Create Release Branch**
16
+ ```bash
17
+ git checkout -b release/v<VERSION>
18
+ ```
19
+
20
+ 3. **Update Version**
21
+ - Edit `lib/tastytrade/version.rb` to bump the version number
22
+
23
+ 4. **Update ROADMAP.md**
24
+ - Review the CHANGELOG.md "Unreleased" section for completed items
25
+ - Find corresponding items in ROADMAP.md and mark them as completed:
26
+ - Change `- [ ]` to `- [x]` for completed items
27
+ - Look for items in all phases, not just Phase 1
28
+ - If an item mentions a GitHub issue number, include "(closes #X)" after marking complete
29
+
30
+ 5. **Update CHANGELOG.md**
31
+ - Move all entries from "Unreleased" to a new version section with today's date
32
+ - Format: `## [X.Y.Z] - YYYY-MM-DD`
33
+ - Create a new empty "Unreleased" section at the top with all subsections:
34
+ ```markdown
35
+ ## [Unreleased]
36
+
37
+ ### Added
38
+ - Nothing yet
39
+
40
+ ### Changed
41
+ - Nothing yet
42
+
43
+ ### Deprecated
44
+ - Nothing yet
45
+
46
+ ### Removed
47
+ - Nothing yet
48
+
49
+ ### Fixed
50
+ - Nothing yet
51
+
52
+ ### Security
53
+ - Nothing yet
54
+ ```
55
+
56
+ 6. **Commit Changes**
57
+ ```bash
58
+ git add lib/tastytrade/version.rb CHANGELOG.md ROADMAP.md
59
+ git commit -m "Release v<VERSION>"
60
+ ```
61
+
62
+ 7. **Push Branch**
63
+ ```bash
64
+ git push -u origin release/v<VERSION>
65
+ ```
66
+
67
+ 8. **Create Pull Request**
68
+ ```bash
69
+ gh pr create --title "Release v<VERSION>" --body "## Release v<VERSION>
70
+
71
+ This PR prepares the release of version <VERSION>.
72
+
73
+ ### Changes
74
+ - Bumped version to <VERSION>
75
+ - Updated CHANGELOG.md with release date
76
+ - Updated ROADMAP.md to mark completed items
77
+
78
+ ### Release Checklist
79
+ - [ ] Version number is correct
80
+ - [ ] CHANGELOG.md is updated with all changes
81
+ - [ ] ROADMAP.md has completed items marked
82
+ - [ ] All tests pass
83
+ - [ ] RuboCop reports no offenses
84
+
85
+ ### Post-Merge Steps
86
+ After merging this PR:
87
+ 1. \`git checkout main && git pull\`
88
+ 2. \`bundle exec rake release\`
89
+ 3. Create a GitHub Release:
90
+ \`\`\`bash
91
+ gh release create v<VERSION> \\
92
+ --title "v<VERSION>" \\
93
+ --generate-notes \\
94
+ --draft
95
+ \`\`\`
96
+ 4. Edit the draft release to add a summary section at the top with key highlights
97
+ 5. Publish the release:
98
+ \`\`\`bash
99
+ gh release edit v<VERSION> --draft=false
100
+ \`\`\`
101
+
102
+ Note: The rake release command will automatically create and push the git tag v<VERSION>"
103
+ ```
104
+
105
+ ## Important Notes
106
+
107
+ - Do NOT run `rake release` as part of the PR - this happens after merge
108
+ - Ensure all tests pass before creating the PR
109
+ - Run RuboCop to ensure code quality
110
+ - The version in the PR title and body should NOT include the 'v' prefix (e.g., "0.2.0" not "v0.2.0")
111
+ - The rake release command will automatically create the git tag with 'v' prefix (e.g., "v0.2.0")
112
+ - You need a RubyGems.org account to run rake release
113
+
114
+ ## Example
115
+
116
+ For a minor version bump from 0.1.0 to 0.2.0:
117
+ - Branch name: `release/v0.2.0`
118
+ - Commit message: `Release v0.2.0`
119
+ - PR title: `Release v0.2.0`
120
+ - Git tag (after merge): `v0.2.0`
data/.env.example ADDED
@@ -0,0 +1,15 @@
1
+ # Schwab API Credentials
2
+ # Copy this file to .env and fill in your actual values
3
+
4
+ # Your Schwab application's client ID
5
+ SCHWAB_CLIENT_ID=your_client_id_here
6
+
7
+ # Your Schwab application's client secret
8
+ SCHWAB_CLIENT_SECRET=your_client_secret_here
9
+
10
+ # The redirect URI configured in your Schwab application
11
+ # Example: http://localhost:3000/callback
12
+ SCHWAB_REDIRECT_URI=your_redirect_uri_here
13
+
14
+ # Optional: Schwab API base URL (defaults to production)
15
+ # SCHWAB_API_BASE_URL=https://api.schwabapi.com
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
data/.rubocop.yml ADDED
@@ -0,0 +1,25 @@
1
+ inherit_gem:
2
+ rubocop-shopify: rubocop.yml
3
+
4
+ AllCops:
5
+ TargetRubyVersion: 3.1
6
+
7
+ # Enable Security cops
8
+ Security:
9
+ Enabled: true
10
+
11
+ # Security cop configurations
12
+ Security/Eval:
13
+ Enabled: true
14
+
15
+ Security/JSONLoad:
16
+ Enabled: true
17
+
18
+ Security/MarshalLoad:
19
+ Enabled: true
20
+
21
+ Security/Open:
22
+ Enabled: true
23
+
24
+ Security/YAMLLoad:
25
+ Enabled: true
data/CHANGELOG.md ADDED
@@ -0,0 +1,115 @@
1
+ ## [Unreleased]
2
+
3
+ ### Added
4
+ - Nothing yet
5
+
6
+ ### Changed
7
+ - Nothing yet
8
+
9
+ ### Deprecated
10
+ - Nothing yet
11
+
12
+ ### Removed
13
+ - Nothing yet
14
+
15
+ ### Fixed
16
+ - Nothing yet
17
+
18
+ ### Security
19
+ - Nothing yet
20
+
21
+ ## [0.2.0] - 2025-08-14
22
+
23
+ ### Added
24
+ - **Comprehensive Account Management System**
25
+ - `Accounts.get_accounts` - Fetch all accounts with optional field filtering
26
+ - `Accounts.get_account` - Get detailed single account information
27
+ - `Accounts.get_positions` - Retrieve account positions with P&L data
28
+ - `Accounts.get_transactions` - Get transaction history with filtering
29
+ - `Accounts.get_orders` - Fetch orders with status and date filtering
30
+ - `Accounts.get_all_orders` - Get orders across all accounts
31
+ - `Accounts.preview_order` - Preview order costs and requirements before placement
32
+ - `Accounts.get_account_numbers` - Retrieve account number mappings
33
+ - `Accounts.get_user_preferences` - Get user trading preferences
34
+
35
+ - **Encrypted Account Number System**
36
+ - `AccountNumberResolver` - Thread-safe resolver for plain to encrypted account numbers
37
+ - Automatic caching with lazy loading and mutex synchronization
38
+ - Transparent usage - developers use plain account numbers, SDK handles encryption
39
+ - Uses `/accounts/accountNumbers` endpoint to fetch account mappings
40
+ - Hash detection logic to distinguish encrypted vs plain account numbers
41
+
42
+ - **Resource Object Wrappers**
43
+ - Configurable response format (`:hash` or `:resource`)
44
+ - Sawyer-style resource objects with method access (e.g., `account.account_number`)
45
+ - Automatic type coercion for dates, times, numbers, and booleans
46
+ - Nested object wrapping with identity preservation
47
+ - Hash-style access still available alongside method access
48
+
49
+ - **Enhanced Configuration**
50
+ - `response_format` option to choose between hash and resource object responses
51
+ - Comprehensive validation for all configuration parameters
52
+ - Backward compatibility maintained with hash format as default
53
+
54
+ - Market Data API endpoints
55
+ - `MarketData.get_quotes` - Fetch quotes for multiple symbols
56
+ - `MarketData.get_quote` - Get detailed quote for single symbol
57
+ - `MarketData.get_quote_history` - Retrieve price history/candles
58
+ - `MarketData.get_movers` - Track market movers by index
59
+ - `MarketData.get_market_hours` - Get market session information
60
+ - Automatic token refresh via `TokenManager`
61
+ - Auto-refreshes tokens when they expire in < 5 minutes
62
+ - Shared across all test scripts for consistent token handling
63
+ - Test scripts for development
64
+ - `bin/test_market_data.rb` - Test all market data endpoints
65
+ - `bin/test_account_numbers.rb` - Comprehensive account endpoint testing
66
+ - `bin/debug_market_data.rb` - Debug response structures
67
+ - `bin/test_oauth_with_credentials.rb` - Test OAuth token refresh
68
+ - `bin/oauth_test.rb` - Interactive OAuth flow testing
69
+
70
+ ### Changed
71
+ - **Account API Integration**
72
+ - All account endpoints now use encrypted account numbers transparently
73
+ - Fixed nested response structure handling (positions under `securitiesAccount`)
74
+ - Enhanced date formatting to preserve full ISO-8601 timestamps
75
+ - Added proper error handling with response body preservation for debugging
76
+
77
+ - **HTTP Client Enhancements**
78
+ - Resource class support in all HTTP methods (GET, POST, PUT, DELETE, PATCH)
79
+ - Response wrapping based on configuration format
80
+ - Automatic resource class determination from response data
81
+ - Enhanced error handling with preserved response bodies
82
+
83
+ - API endpoint routing to support different versioning schemes
84
+ - OAuth endpoints use `/v1/oauth/...`
85
+ - Market data endpoints use `/marketdata/v1/...`
86
+ - Account endpoints use `/trader/v1/accounts/...`
87
+ - Connection builder now uses base URL without version prefix
88
+ - OAuth endpoints hardcoded to `/v1` regardless of configuration
89
+
90
+ ### Fixed
91
+ - **Account API Issues**
92
+ - Positions endpoint now correctly extracts from `securitiesAccount.positions`
93
+ - Transactions endpoint includes required `types` parameter
94
+ - Date format handling preserves full ISO-8601 timestamps
95
+ - Order preview integration with existing accounts module
96
+
97
+ - **Code Quality**
98
+ - All RuboCop style issues resolved
99
+ - Duplicate method definitions removed
100
+ - Proper DateTime handling without deprecated methods
101
+ - String formatting using `format()` instead of `%` operator
102
+
103
+ - Test suite compatibility with new URL structure
104
+ - RuboCop compliance for all code
105
+ - VCR cassette recording for OAuth refresh tokens
106
+
107
+ ## [0.1.0] - 2025-08-12
108
+
109
+ - Initial release
110
+ - Core OAuth 2.0 authentication with Authorization Code flow
111
+ - HTTP client with Faraday middleware stack
112
+ - Exception-only error handling
113
+ - Thread-safe token refresh
114
+ - Configuration management
115
+ - Full test coverage with RSpec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2025 Ryan Hamamura
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,133 @@
1
+ # Schwab
2
+
3
+ Ruby SDK for the Charles Schwab API, providing easy access to trading, market data, and portfolio management endpoints.
4
+
5
+ ## Features
6
+
7
+ - OAuth 2.0 authentication
8
+ - Trading operations (orders, positions)
9
+ - Real-time and historical market data
10
+ - Account and portfolio management
11
+ - Watchlist management
12
+ - Options chains and trading
13
+
14
+ ## Installation
15
+
16
+ Add this line to your application's Gemfile:
17
+
18
+ ```ruby
19
+ gem 'schwab'
20
+ ```
21
+
22
+ And then execute:
23
+
24
+ ```bash
25
+ bundle install
26
+ ```
27
+
28
+ Or install it yourself as:
29
+
30
+ ```bash
31
+ gem install schwab
32
+ ```
33
+
34
+ ## Usage
35
+
36
+ ### Authentication
37
+
38
+ ```ruby
39
+ require 'schwab'
40
+
41
+ client = Schwab::Client.new(
42
+ client_id: 'YOUR_CLIENT_ID',
43
+ client_secret: 'YOUR_CLIENT_SECRET',
44
+ redirect_uri: 'YOUR_REDIRECT_URI'
45
+ )
46
+
47
+ # Get authorization URL
48
+ auth_url = client.authorization_url
49
+
50
+ # After user authorizes, exchange code for token
51
+ client.authorize(code: 'AUTHORIZATION_CODE')
52
+ ```
53
+
54
+ ### Market Data
55
+
56
+ ```ruby
57
+ # Get quote for a symbol
58
+ quote = client.get_quote('AAPL')
59
+
60
+ # Get multiple quotes
61
+ quotes = client.get_quotes(['AAPL', 'GOOGL', 'MSFT'])
62
+
63
+ # Get price history
64
+ history = client.get_price_history('AAPL',
65
+ period_type: 'day',
66
+ period: 10,
67
+ frequency_type: 'minute',
68
+ frequency: 5
69
+ )
70
+ ```
71
+
72
+ ### Trading
73
+
74
+ ```ruby
75
+ # Get positions
76
+ positions = client.get_positions(account_id)
77
+
78
+ # Place an order
79
+ order = client.place_order(account_id, {
80
+ orderType: 'LIMIT',
81
+ symbol: 'AAPL',
82
+ quantity: 100,
83
+ price: 150.00,
84
+ instruction: 'BUY'
85
+ })
86
+
87
+ # Get orders
88
+ orders = client.get_orders(account_id)
89
+ ```
90
+
91
+ ### Account Management
92
+
93
+ ```ruby
94
+ # Get accounts
95
+ accounts = client.get_accounts
96
+
97
+ # Get specific account
98
+ account = client.get_account(account_id)
99
+
100
+ # Get transactions
101
+ transactions = client.get_transactions(account_id)
102
+ ```
103
+
104
+ ## Configuration
105
+
106
+ You can configure the client globally:
107
+
108
+ ```ruby
109
+ Schwab.configure do |config|
110
+ config.client_id = 'YOUR_CLIENT_ID'
111
+ config.client_secret = 'YOUR_CLIENT_SECRET'
112
+ config.redirect_uri = 'YOUR_REDIRECT_URI'
113
+ config.sandbox = true # Use sandbox environment
114
+ end
115
+ ```
116
+
117
+ ## Development
118
+
119
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
120
+
121
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
122
+
123
+ ## Contributing
124
+
125
+ Bug reports and pull requests are welcome on GitHub at https://github.com/ryanhamamura/schwab.
126
+
127
+ ## License
128
+
129
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
130
+
131
+ ## Disclaimer
132
+
133
+ This gem is not affiliated with, endorsed by, or sponsored by Charles Schwab & Co., Inc. Use at your own risk. Trading securities involves risk, and past performance is not indicative of future results.
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
4
+ require "rspec/core/rake_task"
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ require "rubocop/rake_task"
9
+
10
+ RuboCop::RakeTask.new
11
+
12
+ task default: [:spec, :rubocop]