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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/commands/plan.md +13 -0
  3. data/.claude/commands/release-pr.md +12 -0
  4. data/CHANGELOG.md +170 -0
  5. data/README.md +424 -3
  6. data/ROADMAP.md +17 -17
  7. data/lib/tastytrade/cli/history_formatter.rb +304 -0
  8. data/lib/tastytrade/cli/orders.rb +749 -0
  9. data/lib/tastytrade/cli/positions_formatter.rb +114 -0
  10. data/lib/tastytrade/cli.rb +701 -12
  11. data/lib/tastytrade/cli_helpers.rb +111 -14
  12. data/lib/tastytrade/client.rb +7 -0
  13. data/lib/tastytrade/file_store.rb +83 -0
  14. data/lib/tastytrade/instruments/equity.rb +42 -0
  15. data/lib/tastytrade/models/account.rb +160 -2
  16. data/lib/tastytrade/models/account_balance.rb +46 -0
  17. data/lib/tastytrade/models/buying_power_effect.rb +61 -0
  18. data/lib/tastytrade/models/live_order.rb +272 -0
  19. data/lib/tastytrade/models/order_response.rb +106 -0
  20. data/lib/tastytrade/models/order_status.rb +84 -0
  21. data/lib/tastytrade/models/trading_status.rb +200 -0
  22. data/lib/tastytrade/models/transaction.rb +151 -0
  23. data/lib/tastytrade/models.rb +6 -0
  24. data/lib/tastytrade/order.rb +191 -0
  25. data/lib/tastytrade/order_validator.rb +355 -0
  26. data/lib/tastytrade/session.rb +26 -1
  27. data/lib/tastytrade/session_manager.rb +43 -14
  28. data/lib/tastytrade/version.rb +1 -1
  29. data/lib/tastytrade.rb +43 -0
  30. data/spec/exe/tastytrade_spec.rb +1 -1
  31. data/spec/spec_helper.rb +72 -0
  32. data/spec/tastytrade/cli/positions_spec.rb +267 -0
  33. data/spec/tastytrade/cli_auth_spec.rb +5 -0
  34. data/spec/tastytrade/cli_env_login_spec.rb +199 -0
  35. data/spec/tastytrade/cli_helpers_spec.rb +3 -26
  36. data/spec/tastytrade/cli_orders_spec.rb +168 -0
  37. data/spec/tastytrade/cli_status_spec.rb +153 -164
  38. data/spec/tastytrade/file_store_spec.rb +126 -0
  39. data/spec/tastytrade/models/account_balance_spec.rb +103 -0
  40. data/spec/tastytrade/models/account_order_history_spec.rb +229 -0
  41. data/spec/tastytrade/models/account_order_management_spec.rb +271 -0
  42. data/spec/tastytrade/models/account_place_order_spec.rb +125 -0
  43. data/spec/tastytrade/models/account_spec.rb +86 -15
  44. data/spec/tastytrade/models/buying_power_effect_spec.rb +250 -0
  45. data/spec/tastytrade/models/live_order_json_spec.rb +144 -0
  46. data/spec/tastytrade/models/live_order_spec.rb +295 -0
  47. data/spec/tastytrade/models/order_response_spec.rb +96 -0
  48. data/spec/tastytrade/models/order_status_spec.rb +113 -0
  49. data/spec/tastytrade/models/trading_status_spec.rb +260 -0
  50. data/spec/tastytrade/models/transaction_spec.rb +236 -0
  51. data/spec/tastytrade/order_edge_cases_spec.rb +163 -0
  52. data/spec/tastytrade/order_spec.rb +201 -0
  53. data/spec/tastytrade/order_validator_spec.rb +347 -0
  54. data/spec/tastytrade/session_env_spec.rb +169 -0
  55. data/spec/tastytrade/session_manager_spec.rb +43 -33
  56. data/vcr_implementation_plan.md +403 -0
  57. data/vcr_implementation_research.md +330 -0
  58. metadata +50 -18
  59. data/lib/tastytrade/keyring_store.rb +0 -72
  60. 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.2.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/keyring_store.rb
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/keyring_store_spec.rb
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.7.0
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