schwab_rb 1.0.0 → 1.0.1
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 +4 -4
- data/.claude/settings.local.json +3 -1
- data/examples/stream_level_one.rb +1 -1
- data/examples/stream_order_book.rb +1 -1
- data/lib/schwab_rb/stream/message_builder.rb +1 -1
- data/lib/schwab_rb/utils/logger.rb +5 -1
- data/lib/schwab_rb/version.rb +1 -1
- metadata +1 -2
- data/doc/ACCOUNT_MANAGEMENT.md +0 -297
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a575cc586047d31d897d0ec4ba6d35afa1c2c97938a8dbf3e82b292d3b5d74a2
|
|
4
|
+
data.tar.gz: 3c859570ce9831b5b30bc2798d9083d2110d7e9be09065b33a312292334d7963
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3c2a2709207b61685083ff764585ccafe8a722ae798faf4c469fe75617585d65ae89847aa63d4b17bd9315a504a234d212b63226c40acfb2324f4e28199e7fc6
|
|
7
|
+
data.tar.gz: 85799a5ec440620b5c3756b2d86ac007e10d5c5c08be8fd08dc793232c0fb2ad1f918787a8fede962a797cecd7f4bef3cc222a121c285faed8ac06e364551355
|
data/.claude/settings.local.json
CHANGED
|
@@ -16,7 +16,7 @@ Fields = SchwabRb::Stream::Fields
|
|
|
16
16
|
client = SchwabRb::Auth.init_client_easy(
|
|
17
17
|
ENV.fetch("SCHWAB_API_KEY"),
|
|
18
18
|
ENV.fetch("SCHWAB_APP_SECRET"),
|
|
19
|
-
ENV.fetch("
|
|
19
|
+
ENV.fetch("SCHWAB_APP_CALLBACK_URL")
|
|
20
20
|
)
|
|
21
21
|
|
|
22
22
|
stream = SchwabRb::Stream::Client.new(client)
|
|
@@ -16,7 +16,7 @@ Fields = SchwabRb::Stream::Fields
|
|
|
16
16
|
client = SchwabRb::Auth.init_client_easy(
|
|
17
17
|
ENV.fetch("SCHWAB_API_KEY"),
|
|
18
18
|
ENV.fetch("SCHWAB_APP_SECRET"),
|
|
19
|
-
ENV.fetch("
|
|
19
|
+
ENV.fetch("SCHWAB_APP_CALLBACK_URL")
|
|
20
20
|
)
|
|
21
21
|
|
|
22
22
|
stream = SchwabRb::Stream::Client.new(client)
|
|
@@ -19,7 +19,7 @@ module SchwabRb
|
|
|
19
19
|
"SchwabClientCustomerId" => @customer_id,
|
|
20
20
|
"SchwabClientCorrelId" => @correl_id,
|
|
21
21
|
"parameters" => {
|
|
22
|
-
"Authorization" =>
|
|
22
|
+
"Authorization" => access_token,
|
|
23
23
|
"SchwabClientChannel" => channel,
|
|
24
24
|
"SchwabClientFunctionId" => function_id
|
|
25
25
|
}
|
|
@@ -31,7 +31,11 @@ module SchwabRb
|
|
|
31
31
|
|
|
32
32
|
return null_logger if [:null, "/dev/null"].include?(log_destination)
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
if log_destination.is_a?(String) && log_destination.upcase == "STDOUT"
|
|
35
|
+
log_destination = $stdout
|
|
36
|
+
else
|
|
37
|
+
setup_log_file(log_destination)
|
|
38
|
+
end
|
|
35
39
|
|
|
36
40
|
::Logger.new(log_destination, "weekly").tap do |log|
|
|
37
41
|
log.level = parse_log_level(config.log_level)
|
data/lib/schwab_rb/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: schwab_rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Joseph Platta
|
|
@@ -237,7 +237,6 @@ files:
|
|
|
237
237
|
- LICENSE.txt
|
|
238
238
|
- README.md
|
|
239
239
|
- Rakefile
|
|
240
|
-
- doc/ACCOUNT_MANAGEMENT.md
|
|
241
240
|
- doc/LOGGING.md
|
|
242
241
|
- doc/PLACE_ORDER_SAMPLES.md
|
|
243
242
|
- doc/QUICK_START.md
|
data/doc/ACCOUNT_MANAGEMENT.md
DELETED
|
@@ -1,297 +0,0 @@
|
|
|
1
|
-
# Account Management Guide
|
|
2
|
-
|
|
3
|
-
The schwab_rb gem provides a secure and convenient way to manage multiple Schwab accounts using friendly account names instead of exposing account numbers or hashes in your code.
|
|
4
|
-
|
|
5
|
-
## Table of Contents
|
|
6
|
-
|
|
7
|
-
- [Overview](#overview)
|
|
8
|
-
- [Quick Start](#quick-start)
|
|
9
|
-
- [Configuration](#configuration)
|
|
10
|
-
- [Account Names Setup](#account-names-setup)
|
|
11
|
-
- [Using Account Names](#using-account-names)
|
|
12
|
-
- [Security Best Practices](#security-best-practices)
|
|
13
|
-
- [Troubleshooting](#troubleshooting)
|
|
14
|
-
- [API Reference](#api-reference)
|
|
15
|
-
|
|
16
|
-
## Overview
|
|
17
|
-
|
|
18
|
-
Schwab's API requires account hashes for most operations, which:
|
|
19
|
-
- Change periodically (accounts get "rehashed")
|
|
20
|
-
- Are inconvenient to look up and copy
|
|
21
|
-
- Expose sensitive account numbers in code
|
|
22
|
-
|
|
23
|
-
schwab_rb provides an account name mapping system that:
|
|
24
|
-
- **Increases Security**: Account numbers never appear in your code
|
|
25
|
-
- **Improves Usability**: Reference accounts by friendly names like "my_trading_account"
|
|
26
|
-
- **Auto-Updates**: Account hashes refresh automatically
|
|
27
|
-
- **Handles Staleness**: Retries failed requests with fresh hashes
|
|
28
|
-
|
|
29
|
-
## Quick Start
|
|
30
|
-
|
|
31
|
-
### 1. Create Account Names File
|
|
32
|
-
|
|
33
|
-
Create `~/.schwab_rb/account_names.json` with your account mappings:
|
|
34
|
-
|
|
35
|
-
```json
|
|
36
|
-
{
|
|
37
|
-
"my_trading_account": "12345678",
|
|
38
|
-
"my_ira": "87654321",
|
|
39
|
-
"my_roth_ira": "11223344"
|
|
40
|
-
}
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
### 2. Initialize Client and Fetch Hashes
|
|
44
|
-
|
|
45
|
-
```ruby
|
|
46
|
-
require "schwab_rb"
|
|
47
|
-
|
|
48
|
-
# Initialize client
|
|
49
|
-
client = SchwabRb::Auth.init_client_easy(
|
|
50
|
-
ENV['SCHWAB_API_KEY'],
|
|
51
|
-
ENV['SCHWAB_APP_SECRET'],
|
|
52
|
-
ENV['SCHWAB_APP_CALLBACK_URL'],
|
|
53
|
-
ENV['SCHWAB_TOKEN_PATH']
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
# Fetch account numbers and populate hashes
|
|
57
|
-
client.get_account_numbers
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
This automatically creates `~/.schwab_rb/account_hashes.json` with the name-to-hash mappings.
|
|
61
|
-
|
|
62
|
-
### 3. Use Account Names in API Calls
|
|
63
|
-
|
|
64
|
-
```ruby
|
|
65
|
-
# Get account by name
|
|
66
|
-
account = client.get_account(account_name: "my_trading_account")
|
|
67
|
-
|
|
68
|
-
# Place order using account name
|
|
69
|
-
order = client.place_order(order_spec, account_name: "my_ira")
|
|
70
|
-
|
|
71
|
-
# Get transactions
|
|
72
|
-
transactions = client.get_transactions(account_name: "my_roth_ira")
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
## Configuration
|
|
76
|
-
|
|
77
|
-
### Default Paths
|
|
78
|
-
|
|
79
|
-
By default, schwab_rb uses:
|
|
80
|
-
- `schwab_home`: `~/.schwab_rb`
|
|
81
|
-
- `account_hashes_path`: `~/.schwab_rb/account_hashes.json`
|
|
82
|
-
- `account_names_path`: `~/.schwab_rb/account_names.json`
|
|
83
|
-
|
|
84
|
-
### Custom Paths
|
|
85
|
-
|
|
86
|
-
#### Via Environment Variables
|
|
87
|
-
|
|
88
|
-
```bash
|
|
89
|
-
export SCHWAB_HOME="/custom/path"
|
|
90
|
-
export SCHWAB_ACCOUNT_HASHES_PATH="/custom/path/hashes.json"
|
|
91
|
-
export SCHWAB_ACCOUNT_NAMES_PATH="/custom/path/names.json"
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
#### Via Ruby Configuration
|
|
95
|
-
|
|
96
|
-
```ruby
|
|
97
|
-
SchwabRb.configure do |config|
|
|
98
|
-
config.schwab_home = "/custom/path"
|
|
99
|
-
config.account_hashes_path = "/custom/path/hashes.json"
|
|
100
|
-
config.account_names_path = "/custom/path/names.json"
|
|
101
|
-
end
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
## Account Names Setup
|
|
105
|
-
|
|
106
|
-
### File Format
|
|
107
|
-
|
|
108
|
-
`account_names.json` is a simple JSON object mapping friendly names to 8-digit account numbers:
|
|
109
|
-
|
|
110
|
-
```json
|
|
111
|
-
{
|
|
112
|
-
"descriptive_name": "account_number"
|
|
113
|
-
}
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
## Using Account Names
|
|
117
|
-
|
|
118
|
-
### Methods Supporting Account Names
|
|
119
|
-
|
|
120
|
-
All account-specific methods support both `account_hash` and `account_name`:
|
|
121
|
-
|
|
122
|
-
- `get_account(account_name:)` or `get_account(account_hash)`
|
|
123
|
-
- `get_order(order_id, account_name:)`
|
|
124
|
-
- `cancel_order(order_id, account_name:)`
|
|
125
|
-
- `get_account_orders(account_name:)`
|
|
126
|
-
- `place_order(order_spec, account_name:)`
|
|
127
|
-
- `replace_order(order_id, order_spec, account_name:)`
|
|
128
|
-
- `preview_order(order_spec, account_name:)`
|
|
129
|
-
- `get_transactions(account_name:)`
|
|
130
|
-
- `get_transaction(activity_id, account_name:)`
|
|
131
|
-
|
|
132
|
-
### Calling Patterns
|
|
133
|
-
|
|
134
|
-
```ruby
|
|
135
|
-
# Using account name (keyword argument) - RECOMMENDED
|
|
136
|
-
client.get_account(account_name: "my_trading_account")
|
|
137
|
-
|
|
138
|
-
# Using account hash (positional argument) - still works
|
|
139
|
-
client.get_account("ABC123HASH")
|
|
140
|
-
|
|
141
|
-
# Using account hash (keyword argument)
|
|
142
|
-
client.get_account(account_hash: "ABC123HASH")
|
|
143
|
-
|
|
144
|
-
# Priority: account_name always takes precedence
|
|
145
|
-
client.get_account("HASH1", account_name: "my_ira") # Uses "my_ira"
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
### List Available Accounts
|
|
149
|
-
|
|
150
|
-
```ruby
|
|
151
|
-
# Get list of configured account names
|
|
152
|
-
names = client.available_account_names
|
|
153
|
-
# => ["my_trading_account", "my_ira", "my_roth_ira"]
|
|
154
|
-
|
|
155
|
-
puts "Available accounts:"
|
|
156
|
-
names.each { |name| puts " - #{name}" }
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
## Security
|
|
160
|
-
|
|
161
|
-
### 1. Protect Your Files
|
|
162
|
-
|
|
163
|
-
The account files contain sensitive information:
|
|
164
|
-
|
|
165
|
-
```bash
|
|
166
|
-
# Set restrictive permissions
|
|
167
|
-
chmod 600 ~/.schwab_rb/account_names.json
|
|
168
|
-
chmod 600 ~/.schwab_rb/account_hashes.json
|
|
169
|
-
|
|
170
|
-
# Verify permissions
|
|
171
|
-
ls -l ~/.schwab_rb/
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
### 2. Don't Commit to Version Control
|
|
175
|
-
|
|
176
|
-
Add to `.gitignore`:
|
|
177
|
-
|
|
178
|
-
```
|
|
179
|
-
.schwab_rb/
|
|
180
|
-
**/account_names.json
|
|
181
|
-
**/account_hashes.json
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
### 3. Environment-Specific Configs
|
|
185
|
-
|
|
186
|
-
Use different configs per environment:
|
|
187
|
-
|
|
188
|
-
```ruby
|
|
189
|
-
# In development
|
|
190
|
-
SchwabRb.configure do |config|
|
|
191
|
-
config.schwab_home = "~/.schwab_rb/development"
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
# In production
|
|
195
|
-
SchwabRb.configure do |config|
|
|
196
|
-
config.schwab_home = ENV['SCHWAB_CONFIG_PATH']
|
|
197
|
-
end
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
## Troubleshooting
|
|
201
|
-
|
|
202
|
-
### Account Name Not Found
|
|
203
|
-
|
|
204
|
-
**Error**: `Account name 'my_account' not found in account hashes.`
|
|
205
|
-
|
|
206
|
-
**Solutions**:
|
|
207
|
-
1. Run `client.get_account_numbers` to populate hashes
|
|
208
|
-
2. Check spelling in `account_names.json`
|
|
209
|
-
3. Verify account number is correct
|
|
210
|
-
|
|
211
|
-
### Account Numbers File Missing
|
|
212
|
-
|
|
213
|
-
**Error**: `Account names file not found at ~/.schwab_rb/account_names.json`
|
|
214
|
-
|
|
215
|
-
**Solutions**:
|
|
216
|
-
1. Create the file with your account mappings (see [Quick Start](#quick-start))
|
|
217
|
-
2. Set custom path via config if file is elsewhere
|
|
218
|
-
|
|
219
|
-
### Account Not in API Response
|
|
220
|
-
|
|
221
|
-
**Warning**: `Account 'old_account' (98765432) not found in API response.`
|
|
222
|
-
|
|
223
|
-
This warning means an account in your `account_names.json` wasn't returned by the API.
|
|
224
|
-
|
|
225
|
-
**Possible Causes**:
|
|
226
|
-
- Account was closed
|
|
227
|
-
- Wrong account number in `account_names.json`
|
|
228
|
-
- Account not accessible with current API credentials
|
|
229
|
-
|
|
230
|
-
**Actions**:
|
|
231
|
-
1. Verify account status on Schwab website
|
|
232
|
-
2. Check account number in `account_names.json`
|
|
233
|
-
3. Remove closed accounts from config
|
|
234
|
-
|
|
235
|
-
### Stale Account Hashes
|
|
236
|
-
|
|
237
|
-
The gem automatically handles stale hashes:
|
|
238
|
-
1. Request fails with stale hash
|
|
239
|
-
2. Calls `get_account_numbers` to refresh
|
|
240
|
-
3. Retries request with new hash
|
|
241
|
-
4. If still fails, raises original error
|
|
242
|
-
|
|
243
|
-
## API Reference
|
|
244
|
-
|
|
245
|
-
### Client Methods
|
|
246
|
-
|
|
247
|
-
#### `available_account_names`
|
|
248
|
-
|
|
249
|
-
Returns list of configured account names.
|
|
250
|
-
|
|
251
|
-
```ruby
|
|
252
|
-
client.available_account_names
|
|
253
|
-
# => ["my_trading_account", "my_ira"]
|
|
254
|
-
```
|
|
255
|
-
|
|
256
|
-
**Returns**: `Array<String>` - List of account names from `account_names.json`
|
|
257
|
-
**Returns**: `[]` - Empty array if file doesn't exist
|
|
258
|
-
|
|
259
|
-
#### Account-Specific Methods
|
|
260
|
-
|
|
261
|
-
All methods accept either `account_name:` or `account_hash`:
|
|
262
|
-
|
|
263
|
-
```ruby
|
|
264
|
-
# Get account
|
|
265
|
-
client.get_account(account_name: "my_trading_account")
|
|
266
|
-
client.get_account("ABC123HASH")
|
|
267
|
-
|
|
268
|
-
# Get orders
|
|
269
|
-
client.get_account_orders(account_name: "my_ira", max_results: 10)
|
|
270
|
-
|
|
271
|
-
# Place order
|
|
272
|
-
client.place_order(order_spec, account_name: "my_trading_account")
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
### AccountHashManager
|
|
276
|
-
|
|
277
|
-
Direct access to the account hash manager:
|
|
278
|
-
|
|
279
|
-
```ruby
|
|
280
|
-
manager = SchwabRb::AccountHashManager.new
|
|
281
|
-
|
|
282
|
-
# Get available names
|
|
283
|
-
manager.available_account_names
|
|
284
|
-
# => ["my_trading_account", "my_ira"]
|
|
285
|
-
|
|
286
|
-
# Get hash by name
|
|
287
|
-
manager.get_hash_by_name("my_trading_account")
|
|
288
|
-
# => "ABC123HASH"
|
|
289
|
-
|
|
290
|
-
# Get all hashes
|
|
291
|
-
manager.get_all_hashes
|
|
292
|
-
# => {"my_trading_account" => "ABC123HASH", "my_ira" => "XYZ789HASH"}
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
---
|
|
296
|
-
|
|
297
|
-
For more information, see the [main README](../README.md) or visit [github.com/jwplatta/schwab_rb](https://github.com/jwplatta/schwab_rb).
|