tastytrade 0.2.0 → 0.3.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 +4 -4
- data/.claude/commands/plan.md +13 -0
- data/.claude/commands/release-pr.md +12 -0
- data/CHANGELOG.md +170 -0
- data/README.md +424 -3
- data/ROADMAP.md +17 -17
- data/lib/tastytrade/cli/history_formatter.rb +304 -0
- data/lib/tastytrade/cli/orders.rb +749 -0
- data/lib/tastytrade/cli/positions_formatter.rb +114 -0
- data/lib/tastytrade/cli.rb +701 -12
- data/lib/tastytrade/cli_helpers.rb +111 -14
- data/lib/tastytrade/client.rb +7 -0
- data/lib/tastytrade/file_store.rb +83 -0
- data/lib/tastytrade/instruments/equity.rb +42 -0
- data/lib/tastytrade/models/account.rb +160 -2
- data/lib/tastytrade/models/account_balance.rb +46 -0
- data/lib/tastytrade/models/buying_power_effect.rb +61 -0
- data/lib/tastytrade/models/live_order.rb +272 -0
- data/lib/tastytrade/models/order_response.rb +106 -0
- data/lib/tastytrade/models/order_status.rb +84 -0
- data/lib/tastytrade/models/trading_status.rb +200 -0
- data/lib/tastytrade/models/transaction.rb +151 -0
- data/lib/tastytrade/models.rb +6 -0
- data/lib/tastytrade/order.rb +191 -0
- data/lib/tastytrade/order_validator.rb +355 -0
- data/lib/tastytrade/session.rb +26 -1
- data/lib/tastytrade/session_manager.rb +43 -14
- data/lib/tastytrade/version.rb +1 -1
- data/lib/tastytrade.rb +43 -0
- data/spec/exe/tastytrade_spec.rb +1 -1
- data/spec/spec_helper.rb +72 -0
- data/spec/tastytrade/cli/positions_spec.rb +267 -0
- data/spec/tastytrade/cli_auth_spec.rb +5 -0
- data/spec/tastytrade/cli_env_login_spec.rb +199 -0
- data/spec/tastytrade/cli_helpers_spec.rb +3 -26
- data/spec/tastytrade/cli_orders_spec.rb +168 -0
- data/spec/tastytrade/cli_status_spec.rb +153 -164
- data/spec/tastytrade/file_store_spec.rb +126 -0
- data/spec/tastytrade/models/account_balance_spec.rb +103 -0
- data/spec/tastytrade/models/account_order_history_spec.rb +229 -0
- data/spec/tastytrade/models/account_order_management_spec.rb +271 -0
- data/spec/tastytrade/models/account_place_order_spec.rb +125 -0
- data/spec/tastytrade/models/account_spec.rb +86 -15
- data/spec/tastytrade/models/buying_power_effect_spec.rb +250 -0
- data/spec/tastytrade/models/live_order_json_spec.rb +144 -0
- data/spec/tastytrade/models/live_order_spec.rb +295 -0
- data/spec/tastytrade/models/order_response_spec.rb +96 -0
- data/spec/tastytrade/models/order_status_spec.rb +113 -0
- data/spec/tastytrade/models/trading_status_spec.rb +260 -0
- data/spec/tastytrade/models/transaction_spec.rb +236 -0
- data/spec/tastytrade/order_edge_cases_spec.rb +163 -0
- data/spec/tastytrade/order_spec.rb +201 -0
- data/spec/tastytrade/order_validator_spec.rb +347 -0
- data/spec/tastytrade/session_env_spec.rb +169 -0
- data/spec/tastytrade/session_manager_spec.rb +43 -33
- data/vcr_implementation_plan.md +403 -0
- data/vcr_implementation_research.md +330 -0
- metadata +50 -18
- data/lib/tastytrade/keyring_store.rb +0 -72
- data/spec/tastytrade/keyring_store_spec.rb +0 -168
@@ -0,0 +1,330 @@
|
|
1
|
+
# VCR Implementation Research - Best Practices
|
2
|
+
|
3
|
+
## Research Progress
|
4
|
+
|
5
|
+
### Question 1: Test Environment & Credentials
|
6
|
+
**Question**: Do you have access to a Tastytrade sandbox/test account?
|
7
|
+
**Status**: ✅ ANSWERED
|
8
|
+
**Best Practice**: Use sandbox/test accounts for recording. APIs should provide sandbox environments for testing that don't affect production data.
|
9
|
+
**Recommendation**: We should use Tastytrade's sandbox environment for all VCR recordings.
|
10
|
+
**Outstanding**: Need to confirm if you have sandbox credentials.
|
11
|
+
|
12
|
+
### Question 2: How should we handle test credentials?
|
13
|
+
**Question**: Store in .env.test file? GitHub secrets for CI? Other approach?
|
14
|
+
**Status**: ✅ ANSWERED
|
15
|
+
**Best Practice**:
|
16
|
+
- Use environment variables for credentials (12-Factor App practice)
|
17
|
+
- Local: Use .env.test file (gitignored) with dotenv gem
|
18
|
+
- CI: Use GitHub Actions secrets
|
19
|
+
- Filter sensitive data in VCR configuration
|
20
|
+
**Recommendation**:
|
21
|
+
1. Create `.env.test.example` with placeholders
|
22
|
+
2. Use `.env.test` locally (gitignored)
|
23
|
+
3. Store credentials in GitHub secrets for CI
|
24
|
+
4. Configure VCR to filter all sensitive data
|
25
|
+
|
26
|
+
### Question 3: What recording mode should we use?
|
27
|
+
**Question**: :once, :new_episodes, :none, or custom strategy?
|
28
|
+
**Status**: ✅ ANSWERED
|
29
|
+
**Best Practice**:
|
30
|
+
- Use `:once` as default (recommended by VCR documentation)
|
31
|
+
- Use environment variable for re-recording: `VCR_MODE=rec` → `:all`
|
32
|
+
- Use `:none` in CI for safety (prevents accidental API calls)
|
33
|
+
- Avoid `:new_episodes` unless specifically needed (can silently record unmatched requests)
|
34
|
+
**Recommendation**:
|
35
|
+
```ruby
|
36
|
+
vcr_mode = ENV['VCR_MODE'] =~ /rec/i ? :all : :once
|
37
|
+
vcr_mode = :none if ENV['CI']
|
38
|
+
```
|
39
|
+
|
40
|
+
### Question 4: Should we record against production or sandbox API?
|
41
|
+
**Question**: Sandbox vs production for recordings?
|
42
|
+
**Status**: ✅ ANSWERED
|
43
|
+
**Best Practice**:
|
44
|
+
- Always use sandbox/test environments for recording cassettes
|
45
|
+
- Maintain complete isolation from production
|
46
|
+
- Don't change API URLs in test environment - point to real service
|
47
|
+
- Ensure proper compliance and data segregation
|
48
|
+
**Recommendation**: Use Tastytrade sandbox API exclusively for all recordings
|
49
|
+
|
50
|
+
### Question 5: Which test areas are most critical to convert first?
|
51
|
+
**Question**: Authentication, Orders, Account/Balance, or CLI?
|
52
|
+
**Status**: ✅ ANSWERED
|
53
|
+
**Best Practice**:
|
54
|
+
- Start with Authentication/Session tests (foundation for all other tests)
|
55
|
+
- Then Session management (stateful interactions)
|
56
|
+
- Then critical business logic (orders, accounts)
|
57
|
+
- Finally secondary features (CLI, etc.)
|
58
|
+
**Recommendation**: Priority order:
|
59
|
+
1. Authentication/Session tests (fundamental)
|
60
|
+
2. Account/Balance retrieval (frequently used)
|
61
|
+
3. Order placement (high risk, needs accurate testing)
|
62
|
+
4. CLI commands (user-facing, depends on above)
|
63
|
+
|
64
|
+
### Question 6: Should we keep existing mock tests during transition?
|
65
|
+
**Question**: Run both in parallel or replace completely?
|
66
|
+
**Status**: ✅ ANSWERED
|
67
|
+
**Best Practice**:
|
68
|
+
- Can use both VCR and WebMock together
|
69
|
+
- Use `:use_vcr` metadata to enable VCR for specific tests
|
70
|
+
- Gradually transition from mocks to VCR
|
71
|
+
- Keep mocks for simple unit tests, use VCR for integration tests
|
72
|
+
**Recommendation**:
|
73
|
+
1. Keep existing mock tests initially
|
74
|
+
2. Add `:use_vcr` metadata to tests being converted
|
75
|
+
3. Run both in parallel during transition
|
76
|
+
4. Remove mocks after VCR tests are stable
|
77
|
+
|
78
|
+
### Question 7: How should we handle dynamic data in recordings?
|
79
|
+
**Question**: Timestamps, Order IDs, Market prices - custom matchers or freeze time?
|
80
|
+
**Status**: ✅ ANSWERED
|
81
|
+
**Best Practice**:
|
82
|
+
- Use `uri_without_params` for ignoring dynamic URL parameters
|
83
|
+
- Create custom matchers for complex scenarios
|
84
|
+
- Use ERB in cassettes for dynamic content
|
85
|
+
- Filter/replace dynamic data with placeholders
|
86
|
+
**Recommendation**:
|
87
|
+
1. Use `uri_without_params(:timestamp, :order_id)` for URLs
|
88
|
+
2. Filter sensitive/dynamic data in VCR config
|
89
|
+
3. Consider Timecop gem for freezing time in tests
|
90
|
+
4. Use custom matchers for market price matching
|
91
|
+
|
92
|
+
### Question 8: Cassette organization preference?
|
93
|
+
**Question**: One per test, one per file, or grouped by endpoint?
|
94
|
+
**Status**: ✅ ANSWERED
|
95
|
+
**Best Practice**:
|
96
|
+
- Use automatic naming with `configure_rspec_metadata!`
|
97
|
+
- Organize by API endpoint/functionality in subdirectories
|
98
|
+
- One cassette per test example (automatic with metadata)
|
99
|
+
- Group related cassettes in subdirectories
|
100
|
+
**Recommendation**:
|
101
|
+
```
|
102
|
+
spec/fixtures/vcr_cassettes/
|
103
|
+
authentication/
|
104
|
+
accounts/
|
105
|
+
orders/
|
106
|
+
positions/
|
107
|
+
```
|
108
|
+
With automatic naming: `ClassName/test_description.yml`
|
109
|
+
|
110
|
+
### Question 9: How should cassettes be managed in CI?
|
111
|
+
**Question**: Commit to repo, Git LFS, or generate fresh?
|
112
|
+
**Status**: ✅ ANSWERED
|
113
|
+
**Best Practice**:
|
114
|
+
- Commit cassettes to repo for CI reuse (faster builds)
|
115
|
+
- Use Git LFS only if cassettes are very large
|
116
|
+
- Use shallow clones in CI (`fetch-depth: 1`)
|
117
|
+
- Set recording mode to `:none` in CI
|
118
|
+
**Recommendation**:
|
119
|
+
1. Commit cassettes directly to repo (unless >100MB)
|
120
|
+
2. Use `.gitattributes` to reduce diff noise
|
121
|
+
3. Configure CI with `VCR_MODE=none`
|
122
|
+
4. Use `fetch-depth: 1` in GitHub Actions
|
123
|
+
|
124
|
+
### Question 10: Should we implement automatic cassette refresh?
|
125
|
+
**Question**: Monthly refresh, manual, or automated detection?
|
126
|
+
**Status**: ✅ ANSWERED
|
127
|
+
**Best Practice**:
|
128
|
+
- No built-in auto-expiration in VCR (feature request)
|
129
|
+
- Delete cassettes liberally when in doubt
|
130
|
+
- Use environment variable for re-recording
|
131
|
+
- Implement custom age-checking if needed
|
132
|
+
**Recommendation**:
|
133
|
+
1. Manual refresh with `VCR_MODE=rec bundle exec rspec`
|
134
|
+
2. Create rake task for bulk cassette deletion by age
|
135
|
+
3. Document refresh schedule (e.g., monthly)
|
136
|
+
4. Consider custom age-checker in VCR config
|
137
|
+
|
138
|
+
### Question 11: How to handle rate-limited endpoints?
|
139
|
+
**Question**: Add delays or use specific cassettes?
|
140
|
+
**Status**: ✅ ANSWERED
|
141
|
+
**Best Practice**:
|
142
|
+
- Build throttling into the API client itself
|
143
|
+
- VCR eliminates rate limit issues during playback
|
144
|
+
- Record cassettes respecting rate limits initially
|
145
|
+
- Use `:once` mode to avoid re-recording
|
146
|
+
**Recommendation**:
|
147
|
+
1. Add rate limiting to API client (not just tests)
|
148
|
+
2. Record cassettes once with proper delays
|
149
|
+
3. Playback doesn't need delays (cassettes replay instantly)
|
150
|
+
4. Consider separate cassettes for rate-limited endpoints
|
151
|
+
|
152
|
+
### Question 12: WebSocket/streaming endpoints?
|
153
|
+
**Question**: Does the API have real-time endpoints needing special handling?
|
154
|
+
**Status**: ✅ ANSWERED
|
155
|
+
**Best Practice**:
|
156
|
+
- Use specialized libraries like `simple-websocket-vcr` for WebSockets
|
157
|
+
- Standard VCR doesn't handle WebSocket protocol
|
158
|
+
- Record multiple messages/frames in WebSocket sessions
|
159
|
+
- Consider excluding real-time endpoints from VCR
|
160
|
+
**Recommendation**:
|
161
|
+
1. Check if Tastytrade API has WebSocket endpoints
|
162
|
+
2. If yes, use `simple-websocket-vcr` gem
|
163
|
+
3. If no, standard VCR is sufficient
|
164
|
+
4. Mock WebSocket connections for unit tests
|
165
|
+
|
166
|
+
### Question 13: Should we create a proof-of-concept first?
|
167
|
+
**Question**: Convert one simple test file first?
|
168
|
+
**Status**: ✅ ANSWERED
|
169
|
+
**Best Practice**:
|
170
|
+
- Start with single external service/API wrapper
|
171
|
+
- Create dedicated API wrapper classes
|
172
|
+
- Test wrapper with VCR, mock wrapper elsewhere
|
173
|
+
- Run tests twice (record then replay)
|
174
|
+
**Recommendation**:
|
175
|
+
1. YES - Start with proof-of-concept
|
176
|
+
2. Choose Session or Client class first
|
177
|
+
3. Establish patterns and conventions
|
178
|
+
4. Document learnings before full rollout
|
179
|
+
|
180
|
+
### Question 14: Compliance or security requirements?
|
181
|
+
**Question**: Extra sanitization for financial data? Regulatory requirements?
|
182
|
+
**Status**: ✅ ANSWERED
|
183
|
+
**Best Practice**:
|
184
|
+
- Filter all PII from cassettes (names, addresses, SSNs, account numbers)
|
185
|
+
- Use minimum necessary data for tests
|
186
|
+
- Implement access controls for test data
|
187
|
+
- Regular audits of cassette content
|
188
|
+
**Recommendation**:
|
189
|
+
1. Enhance VCR filter_sensitive_data for all PII
|
190
|
+
2. Use synthetic test data where possible
|
191
|
+
3. Document data handling procedures
|
192
|
+
4. Store cassettes securely (encrypted if needed)
|
193
|
+
5. Regular review of cassettes for leaked data
|
194
|
+
|
195
|
+
## Summary
|
196
|
+
|
197
|
+
### Questions Answered by Best Practices (10/14)
|
198
|
+
1. ✅ Test environment - Use sandbox
|
199
|
+
2. ✅ Credentials handling - .env.test + GitHub secrets
|
200
|
+
3. ✅ Recording mode - :once default, :none in CI
|
201
|
+
4. ✅ Production vs sandbox - Always use sandbox
|
202
|
+
5. ✅ Test priorities - Auth → Account → Orders → CLI
|
203
|
+
6. ✅ Migration strategy - Keep mocks initially, parallel transition
|
204
|
+
7. ✅ Dynamic data - Custom matchers and filters
|
205
|
+
8. ✅ Cassette organization - Auto-naming by endpoint
|
206
|
+
9. ✅ CI management - Commit cassettes, use :none mode
|
207
|
+
10. ✅ Refresh strategy - Manual with rake task
|
208
|
+
11. ✅ Rate limiting - Build into client, record once
|
209
|
+
12. ✅ WebSocket - Use specialized gem if needed
|
210
|
+
13. ✅ Proof-of-concept - Yes, start small
|
211
|
+
14. ✅ Compliance - Filter all PII, secure storage
|
212
|
+
|
213
|
+
### Outstanding Questions for User (1/14)
|
214
|
+
1. ~~**Do you have Tastytrade sandbox credentials?**~~ - ✅ CONFIRMED: User has sandbox credentials
|
215
|
+
|
216
|
+
### Critical Sandbox Behavior Note
|
217
|
+
**IMPORTANT**: Tastytrade sandbox endpoints behave like production - they only route orders during normal market hours. This impacts:
|
218
|
+
- Order placement tests (will fail outside market hours)
|
219
|
+
- Order validation tests (may behave differently based on market status)
|
220
|
+
- Any tests that depend on real-time market data
|
221
|
+
|
222
|
+
### Handling Market Hours Limitation
|
223
|
+
|
224
|
+
#### Strategy 1: Time-Independent Cassettes (RECOMMENDED)
|
225
|
+
1. **Record cassettes during market hours**
|
226
|
+
- Schedule recording sessions during market hours (9:30 AM - 4:00 PM ET)
|
227
|
+
- Use a specific day/time for consistency
|
228
|
+
- Document the recording time in cassette metadata
|
229
|
+
|
230
|
+
2. **Use `:once` mode strictly**
|
231
|
+
- Never re-record automatically
|
232
|
+
- Cassettes remain valid regardless of current time
|
233
|
+
- Tests pass 24/7 once recorded
|
234
|
+
|
235
|
+
3. **Separate market-dependent tests**
|
236
|
+
```ruby
|
237
|
+
context "market hour dependent", :market_hours_only do
|
238
|
+
# Tests that need live market
|
239
|
+
end
|
240
|
+
|
241
|
+
context "market hour independent", :vcr do
|
242
|
+
# Most tests with cassettes
|
243
|
+
end
|
244
|
+
```
|
245
|
+
|
246
|
+
#### Strategy 2: Mock Market Hours in Tests
|
247
|
+
1. **Use Timecop to freeze time during playback**
|
248
|
+
```ruby
|
249
|
+
around(:each, :vcr) do |example|
|
250
|
+
# Freeze to a known market hour when cassette was recorded
|
251
|
+
Timecop.freeze(cassette_recorded_at) do
|
252
|
+
example.run
|
253
|
+
end
|
254
|
+
end
|
255
|
+
```
|
256
|
+
|
257
|
+
2. **Add metadata to cassettes**
|
258
|
+
```ruby
|
259
|
+
VCR.configure do |c|
|
260
|
+
c.before_record do |interaction|
|
261
|
+
interaction.response.headers['X-Cassette-Recorded-At'] = Time.current.iso8601
|
262
|
+
interaction.response.headers['X-Market-Status'] = market_open? ? 'open' : 'closed'
|
263
|
+
end
|
264
|
+
end
|
265
|
+
```
|
266
|
+
|
267
|
+
### Handling Sandbox Credentials
|
268
|
+
|
269
|
+
#### Secure Credential Management
|
270
|
+
1. **Local Development (.env.test)**
|
271
|
+
```bash
|
272
|
+
# .env.test (gitignored)
|
273
|
+
TASTYTRADE_SANDBOX_USERNAME=your_sandbox_username
|
274
|
+
TASTYTRADE_SANDBOX_PASSWORD=your_sandbox_password
|
275
|
+
TASTYTRADE_SANDBOX_ACCOUNT=your_sandbox_account_number
|
276
|
+
```
|
277
|
+
|
278
|
+
2. **CI/CD (GitHub Secrets)**
|
279
|
+
- Store same credentials as GitHub secrets
|
280
|
+
- Reference in workflow: `${{ secrets.TASTYTRADE_SANDBOX_USERNAME }}`
|
281
|
+
|
282
|
+
3. **VCR Configuration Enhancement**
|
283
|
+
```ruby
|
284
|
+
VCR.configure do |config|
|
285
|
+
# Enhanced filtering for Tastytrade-specific data
|
286
|
+
config.filter_sensitive_data('<SANDBOX_USERNAME>') { ENV['TASTYTRADE_SANDBOX_USERNAME'] }
|
287
|
+
config.filter_sensitive_data('<SANDBOX_ACCOUNT>') { ENV['TASTYTRADE_SANDBOX_ACCOUNT'] }
|
288
|
+
|
289
|
+
# Filter account numbers from responses
|
290
|
+
config.before_record do |interaction|
|
291
|
+
if interaction.response.body
|
292
|
+
body = interaction.response.body
|
293
|
+
# Replace any account numbers in response
|
294
|
+
body.gsub!(/5W[A-Z0-9]{6}/, '<ACCOUNT_NUMBER>')
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
```
|
299
|
+
|
300
|
+
4. **Test Helper for Sandbox Sessions**
|
301
|
+
```ruby
|
302
|
+
# spec/support/sandbox_helpers.rb
|
303
|
+
module SandboxHelpers
|
304
|
+
def sandbox_session
|
305
|
+
@sandbox_session ||= VCR.use_cassette('authentication/sandbox_login') do
|
306
|
+
Tastytrade::Session.new(
|
307
|
+
username: ENV['TASTYTRADE_SANDBOX_USERNAME'],
|
308
|
+
password: ENV['TASTYTRADE_SANDBOX_PASSWORD'],
|
309
|
+
is_test: true
|
310
|
+
).login
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
def with_market_hours_check
|
315
|
+
if !VCR.current_cassette && !market_open?
|
316
|
+
skip "Skipping test - market closed and no cassette available"
|
317
|
+
end
|
318
|
+
yield
|
319
|
+
end
|
320
|
+
end
|
321
|
+
```
|
322
|
+
|
323
|
+
### Recommended Implementation Order (UPDATED)
|
324
|
+
1. ~~Obtain/confirm sandbox credentials~~ ✅ Complete
|
325
|
+
2. **Set up credential management** (.env.test + GitHub secrets)
|
326
|
+
3. **Record initial cassettes during market hours**
|
327
|
+
4. Create proof-of-concept with Session class
|
328
|
+
5. Establish VCR helper patterns with market hour handling
|
329
|
+
6. Convert tests incrementally following priority order
|
330
|
+
7. Document recording schedule and market hour dependencies
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tastytrade
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Hamamura
|
@@ -37,20 +37,6 @@ dependencies:
|
|
37
37
|
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
39
|
version: '2.2'
|
40
|
-
- !ruby/object:Gem::Dependency
|
41
|
-
name: keyring
|
42
|
-
requirement: !ruby/object:Gem::Requirement
|
43
|
-
requirements:
|
44
|
-
- - "~>"
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
version: '0.4'
|
47
|
-
type: :runtime
|
48
|
-
prerelease: false
|
49
|
-
version_requirements: !ruby/object:Gem::Requirement
|
50
|
-
requirements:
|
51
|
-
- - "~>"
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '0.4'
|
54
40
|
- !ruby/object:Gem::Dependency
|
55
41
|
name: pastel
|
56
42
|
requirement: !ruby/object:Gem::Requirement
|
@@ -177,6 +163,20 @@ dependencies:
|
|
177
163
|
- - "~>"
|
178
164
|
- !ruby/object:Gem::Version
|
179
165
|
version: '0.22'
|
166
|
+
- !ruby/object:Gem::Dependency
|
167
|
+
name: vcr
|
168
|
+
requirement: !ruby/object:Gem::Requirement
|
169
|
+
requirements:
|
170
|
+
- - "~>"
|
171
|
+
- !ruby/object:Gem::Version
|
172
|
+
version: '6.3'
|
173
|
+
type: :development
|
174
|
+
prerelease: false
|
175
|
+
version_requirements: !ruby/object:Gem::Requirement
|
176
|
+
requirements:
|
177
|
+
- - "~>"
|
178
|
+
- !ruby/object:Gem::Version
|
179
|
+
version: '6.3'
|
180
180
|
- !ruby/object:Gem::Dependency
|
181
181
|
name: webmock
|
182
182
|
requirement: !ruby/object:Gem::Requirement
|
@@ -215,6 +215,7 @@ executables:
|
|
215
215
|
extensions: []
|
216
216
|
extra_rdoc_files: []
|
217
217
|
files:
|
218
|
+
- ".claude/commands/plan.md"
|
218
219
|
- ".claude/commands/release-pr.md"
|
219
220
|
- ".github/ISSUE_TEMPLATE/feature_request.md"
|
220
221
|
- ".github/ISSUE_TEMPLATE/roadmap_task.md"
|
@@ -238,40 +239,71 @@ files:
|
|
238
239
|
- exe/tastytrade
|
239
240
|
- lib/tastytrade.rb
|
240
241
|
- lib/tastytrade/cli.rb
|
242
|
+
- lib/tastytrade/cli/history_formatter.rb
|
243
|
+
- lib/tastytrade/cli/orders.rb
|
244
|
+
- lib/tastytrade/cli/positions_formatter.rb
|
241
245
|
- lib/tastytrade/cli_config.rb
|
242
246
|
- lib/tastytrade/cli_helpers.rb
|
243
247
|
- lib/tastytrade/client.rb
|
244
|
-
- lib/tastytrade/
|
248
|
+
- lib/tastytrade/file_store.rb
|
249
|
+
- lib/tastytrade/instruments/equity.rb
|
245
250
|
- lib/tastytrade/models.rb
|
246
251
|
- lib/tastytrade/models/account.rb
|
247
252
|
- lib/tastytrade/models/account_balance.rb
|
248
253
|
- lib/tastytrade/models/base.rb
|
254
|
+
- lib/tastytrade/models/buying_power_effect.rb
|
249
255
|
- lib/tastytrade/models/current_position.rb
|
256
|
+
- lib/tastytrade/models/live_order.rb
|
257
|
+
- lib/tastytrade/models/order_response.rb
|
258
|
+
- lib/tastytrade/models/order_status.rb
|
259
|
+
- lib/tastytrade/models/trading_status.rb
|
260
|
+
- lib/tastytrade/models/transaction.rb
|
250
261
|
- lib/tastytrade/models/user.rb
|
262
|
+
- lib/tastytrade/order.rb
|
263
|
+
- lib/tastytrade/order_validator.rb
|
251
264
|
- lib/tastytrade/session.rb
|
252
265
|
- lib/tastytrade/session_manager.rb
|
253
266
|
- lib/tastytrade/version.rb
|
254
267
|
- sig/tastytrade.rbs
|
255
268
|
- spec/exe/tastytrade_spec.rb
|
256
269
|
- spec/spec_helper.rb
|
270
|
+
- spec/tastytrade/cli/positions_spec.rb
|
257
271
|
- spec/tastytrade/cli_accounts_spec.rb
|
258
272
|
- spec/tastytrade/cli_auth_spec.rb
|
259
273
|
- spec/tastytrade/cli_config_spec.rb
|
274
|
+
- spec/tastytrade/cli_env_login_spec.rb
|
260
275
|
- spec/tastytrade/cli_helpers_spec.rb
|
261
276
|
- spec/tastytrade/cli_interactive_spec.rb
|
262
277
|
- spec/tastytrade/cli_logout_spec.rb
|
278
|
+
- spec/tastytrade/cli_orders_spec.rb
|
263
279
|
- spec/tastytrade/cli_select_spec.rb
|
264
280
|
- spec/tastytrade/cli_status_spec.rb
|
265
281
|
- spec/tastytrade/client_spec.rb
|
266
|
-
- spec/tastytrade/
|
282
|
+
- spec/tastytrade/file_store_spec.rb
|
267
283
|
- spec/tastytrade/models/account_balance_spec.rb
|
284
|
+
- spec/tastytrade/models/account_order_history_spec.rb
|
285
|
+
- spec/tastytrade/models/account_order_management_spec.rb
|
286
|
+
- spec/tastytrade/models/account_place_order_spec.rb
|
268
287
|
- spec/tastytrade/models/account_spec.rb
|
269
288
|
- spec/tastytrade/models/base_spec.rb
|
289
|
+
- spec/tastytrade/models/buying_power_effect_spec.rb
|
270
290
|
- spec/tastytrade/models/current_position_spec.rb
|
291
|
+
- spec/tastytrade/models/live_order_json_spec.rb
|
292
|
+
- spec/tastytrade/models/live_order_spec.rb
|
293
|
+
- spec/tastytrade/models/order_response_spec.rb
|
294
|
+
- spec/tastytrade/models/order_status_spec.rb
|
295
|
+
- spec/tastytrade/models/trading_status_spec.rb
|
296
|
+
- spec/tastytrade/models/transaction_spec.rb
|
271
297
|
- spec/tastytrade/models/user_spec.rb
|
298
|
+
- spec/tastytrade/order_edge_cases_spec.rb
|
299
|
+
- spec/tastytrade/order_spec.rb
|
300
|
+
- spec/tastytrade/order_validator_spec.rb
|
301
|
+
- spec/tastytrade/session_env_spec.rb
|
272
302
|
- spec/tastytrade/session_manager_spec.rb
|
273
303
|
- spec/tastytrade/session_spec.rb
|
274
304
|
- spec/tastytrade_spec.rb
|
305
|
+
- vcr_implementation_plan.md
|
306
|
+
- vcr_implementation_research.md
|
275
307
|
homepage: https://github.com/ryanhamamura/tastytrade
|
276
308
|
licenses:
|
277
309
|
- MIT
|
@@ -297,7 +329,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
297
329
|
- !ruby/object:Gem::Version
|
298
330
|
version: '0'
|
299
331
|
requirements: []
|
300
|
-
rubygems_version: 3.
|
332
|
+
rubygems_version: 3.6.9
|
301
333
|
specification_version: 4
|
302
334
|
summary: Unofficial Ruby SDK for the Tastytrade API
|
303
335
|
test_files: []
|
@@ -1,72 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "keyring"
|
4
|
-
|
5
|
-
module Tastytrade
|
6
|
-
# Secure credential storage using system keyring
|
7
|
-
class KeyringStore
|
8
|
-
SERVICE_NAME = "tastytrade-ruby"
|
9
|
-
|
10
|
-
class << self
|
11
|
-
# Store a credential securely
|
12
|
-
#
|
13
|
-
# @param key [String] The credential key
|
14
|
-
# @param value [String] The credential value
|
15
|
-
# @return [Boolean] Success status
|
16
|
-
def set(key, value)
|
17
|
-
return false if key.nil? || value.nil?
|
18
|
-
|
19
|
-
backend.set_password(SERVICE_NAME, key.to_s, value.to_s)
|
20
|
-
true
|
21
|
-
rescue StandardError => e
|
22
|
-
warn "Failed to store credential: #{e.message}"
|
23
|
-
false
|
24
|
-
end
|
25
|
-
|
26
|
-
# Retrieve a credential
|
27
|
-
#
|
28
|
-
# @param key [String] The credential key
|
29
|
-
# @return [String, nil] The credential value or nil if not found
|
30
|
-
def get(key)
|
31
|
-
return nil if key.nil?
|
32
|
-
|
33
|
-
backend.get_password(SERVICE_NAME, key.to_s)
|
34
|
-
rescue StandardError => e
|
35
|
-
warn "Failed to retrieve credential: #{e.message}"
|
36
|
-
nil
|
37
|
-
end
|
38
|
-
|
39
|
-
# Delete a credential
|
40
|
-
#
|
41
|
-
# @param key [String] The credential key
|
42
|
-
# @return [Boolean] Success status
|
43
|
-
def delete(key)
|
44
|
-
return false if key.nil?
|
45
|
-
|
46
|
-
backend.delete_password(SERVICE_NAME, key.to_s)
|
47
|
-
true
|
48
|
-
rescue StandardError => e
|
49
|
-
warn "Failed to delete credential: #{e.message}"
|
50
|
-
false
|
51
|
-
end
|
52
|
-
|
53
|
-
# Check if keyring is available
|
54
|
-
#
|
55
|
-
# @return [Boolean] True if keyring backend is available
|
56
|
-
def available?
|
57
|
-
!backend.nil?
|
58
|
-
rescue StandardError
|
59
|
-
false
|
60
|
-
end
|
61
|
-
|
62
|
-
private
|
63
|
-
|
64
|
-
def backend
|
65
|
-
@backend ||= Keyring.new
|
66
|
-
rescue StandardError => e
|
67
|
-
warn "Keyring not available: #{e.message}"
|
68
|
-
nil
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|