schwab_rb 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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/.claude/settings.local.json +9 -0
  3. data/.rspec_status +209 -180
  4. data/CLAUDE.md +137 -0
  5. data/README.md +3 -3
  6. data/examples/fetch_account_numbers.rb +12 -15
  7. data/examples/fetch_user_preferences.rb +16 -19
  8. data/lib/schwab_rb/account.rb +1 -1
  9. data/lib/schwab_rb/auth/auth_context.rb +1 -1
  10. data/lib/schwab_rb/auth/init_client_easy.rb +29 -31
  11. data/lib/schwab_rb/auth/init_client_login.rb +24 -21
  12. data/lib/schwab_rb/auth/login_flow_server.rb +2 -2
  13. data/lib/schwab_rb/auth/token.rb +1 -1
  14. data/lib/schwab_rb/auth/token_manager.rb +5 -7
  15. data/lib/schwab_rb/clients/async_client.rb +25 -27
  16. data/lib/schwab_rb/clients/base_client.rb +22 -16
  17. data/lib/schwab_rb/clients/client.rb +14 -14
  18. data/lib/schwab_rb/configuration.rb +4 -4
  19. data/lib/schwab_rb/data_objects/account.rb +2 -2
  20. data/lib/schwab_rb/data_objects/instrument.rb +1 -1
  21. data/lib/schwab_rb/data_objects/market_hours.rb +43 -33
  22. data/lib/schwab_rb/data_objects/market_movers.rb +98 -0
  23. data/lib/schwab_rb/data_objects/option.rb +2 -2
  24. data/lib/schwab_rb/data_objects/option_chain.rb +7 -7
  25. data/lib/schwab_rb/data_objects/option_expiration_chain.rb +26 -25
  26. data/lib/schwab_rb/data_objects/order.rb +7 -6
  27. data/lib/schwab_rb/data_objects/order_leg.rb +5 -5
  28. data/lib/schwab_rb/data_objects/order_preview.rb +13 -16
  29. data/lib/schwab_rb/data_objects/position.rb +4 -4
  30. data/lib/schwab_rb/data_objects/price_history.rb +27 -19
  31. data/lib/schwab_rb/data_objects/quote.rb +6 -6
  32. data/lib/schwab_rb/data_objects/transaction.rb +6 -6
  33. data/lib/schwab_rb/data_objects/user_preferences.rb +3 -3
  34. data/lib/schwab_rb/market_hours.rb +5 -5
  35. data/lib/schwab_rb/movers.rb +16 -16
  36. data/lib/schwab_rb/orders/builder.rb +5 -5
  37. data/lib/schwab_rb/orders/destination.rb +12 -12
  38. data/lib/schwab_rb/orders/duration.rb +7 -7
  39. data/lib/schwab_rb/orders/equity_instructions.rb +4 -4
  40. data/lib/schwab_rb/orders/instruments.rb +8 -8
  41. data/lib/schwab_rb/orders/price_link_basis.rb +9 -9
  42. data/lib/schwab_rb/orders/price_link_type.rb +3 -3
  43. data/lib/schwab_rb/orders/session.rb +4 -4
  44. data/lib/schwab_rb/orders/special_instruction.rb +3 -3
  45. data/lib/schwab_rb/orders/stop_price_link_basis.rb +9 -9
  46. data/lib/schwab_rb/orders/stop_price_link_type.rb +3 -3
  47. data/lib/schwab_rb/orders/stop_type.rb +5 -5
  48. data/lib/schwab_rb/orders/tax_lot_method.rb +7 -7
  49. data/lib/schwab_rb/price_history.rb +8 -8
  50. data/lib/schwab_rb/quote.rb +5 -5
  51. data/lib/schwab_rb/transaction.rb +15 -15
  52. data/lib/schwab_rb/utils/logger.rb +11 -15
  53. data/lib/schwab_rb/utils/redactor.rb +23 -25
  54. data/lib/schwab_rb/version.rb +1 -1
  55. data/lib/schwab_rb.rb +1 -0
  56. metadata +6 -2
@@ -2,9 +2,9 @@ module SchwabRb
2
2
  module Orders
3
3
  module SpecialInstruction
4
4
  # Special instruction for trades.
5
- ALL_OR_NONE = 'ALL_OR_NONE'
6
- DO_NOT_REDUCE = 'DO_NOT_REDUCE'
7
- ALL_OR_NONE_DO_NOT_REDUCE = 'ALL_OR_NONE_DO_NOT_REDUCE'
5
+ ALL_OR_NONE = "ALL_OR_NONE"
6
+ DO_NOT_REDUCE = "DO_NOT_REDUCE"
7
+ ALL_OR_NONE_DO_NOT_REDUCE = "ALL_OR_NONE_DO_NOT_REDUCE"
8
8
  end
9
9
  end
10
10
  end
@@ -1,15 +1,15 @@
1
1
  module SchwabRb
2
2
  module Orders
3
3
  module StopPriceLinkBasis
4
- MANUAL = 'MANUAL'
5
- BASE = 'BASE'
6
- TRIGGER = 'TRIGGER'
7
- LAST = 'LAST'
8
- BID = 'BID'
9
- ASK = 'ASK'
10
- ASK_BID = 'ASK_BID'
11
- MARK = 'MARK'
12
- AVERAGE = 'AVERAGE'
4
+ MANUAL = "MANUAL"
5
+ BASE = "BASE"
6
+ TRIGGER = "TRIGGER"
7
+ LAST = "LAST"
8
+ BID = "BID"
9
+ ASK = "ASK"
10
+ ASK_BID = "ASK_BID"
11
+ MARK = "MARK"
12
+ AVERAGE = "AVERAGE"
13
13
  end
14
14
  end
15
15
  end
@@ -1,9 +1,9 @@
1
1
  module SchwabRb
2
2
  module Orders
3
3
  module StopPriceLinkType
4
- VALUE = 'VALUE'
5
- PERCENT = 'PERCENT'
6
- TICK = 'TICK'
4
+ VALUE = "VALUE"
5
+ PERCENT = "PERCENT"
6
+ TICK = "TICK"
7
7
  end
8
8
  end
9
9
  end
@@ -1,11 +1,11 @@
1
1
  module SchwabRb
2
2
  module Orders
3
3
  module StopType
4
- STANDARD = 'STANDARD'
5
- BID = 'BID'
6
- ASK = 'ASK'
7
- LAST = 'LAST'
8
- MARK = 'MARK'
4
+ STANDARD = "STANDARD"
5
+ BID = "BID"
6
+ ASK = "ASK"
7
+ LAST = "LAST"
8
+ MARK = "MARK"
9
9
  end
10
10
  end
11
11
  end
@@ -1,13 +1,13 @@
1
1
  module SchwabRb
2
2
  module Orders
3
3
  module TaxLotMethod
4
- FIFO = 'FIFO'
5
- LIFO = 'LIFO'
6
- HIGH_COST = 'HIGH_COST'
7
- LOW_COST = 'LOW_COST'
8
- AVERAGE_COST = 'AVERAGE_COST'
9
- SPECIFIC_LOT = 'SPECIFIC_LOT'
10
- LOSS_HARVESTER = 'LOSS_HARVESTER'
4
+ FIFO = "FIFO"
5
+ LIFO = "LIFO"
6
+ HIGH_COST = "HIGH_COST"
7
+ LOW_COST = "LOW_COST"
8
+ AVERAGE_COST = "AVERAGE_COST"
9
+ SPECIFIC_LOT = "SPECIFIC_LOT"
10
+ LOSS_HARVESTER = "LOSS_HARVESTER"
11
11
  end
12
12
  end
13
13
  end
@@ -3,10 +3,10 @@
3
3
  module SchwabRb
4
4
  class PriceHistory
5
5
  module PeriodTypes
6
- DAY = 'day'
7
- MONTH = 'month'
8
- YEAR = 'year'
9
- YEAR_TO_DATE = 'ytd'
6
+ DAY = "day"
7
+ MONTH = "month"
8
+ YEAR = "year"
9
+ YEAR_TO_DATE = "ytd"
10
10
  end
11
11
 
12
12
  module Periods
@@ -34,10 +34,10 @@ module SchwabRb
34
34
  end
35
35
 
36
36
  module FrequencyTypes
37
- MINUTE = 'minute'
38
- DAILY = 'daily'
39
- WEEKLY = 'weekly'
40
- MONTHLY = 'monthly'
37
+ MINUTE = "minute"
38
+ DAILY = "daily"
39
+ WEEKLY = "weekly"
40
+ MONTHLY = "monthly"
41
41
  end
42
42
 
43
43
  module Frequencies
@@ -3,11 +3,11 @@
3
3
  module SchwabRb
4
4
  class Quote
5
5
  module Types
6
- QUOTE = 'quote'
7
- FUNDAMENTAL = 'fundamental'
8
- EXTENDED = 'extended'
9
- REFERENCE = 'reference'
10
- REGULAR = 'regular'
6
+ QUOTE = "quote"
7
+ FUNDAMENTAL = "fundamental"
8
+ EXTENDED = "extended"
9
+ REFERENCE = "reference"
10
+ REGULAR = "regular"
11
11
  end
12
12
  end
13
13
  end
@@ -3,21 +3,21 @@
3
3
  module SchwabRb
4
4
  class Transaction
5
5
  module Types
6
- TRADE = 'TRADE'
7
- RECEIVE_AND_DELIVER = 'RECEIVE_AND_DELIVER'
8
- DIVIDEND_OR_INTEREST = 'DIVIDEND_OR_INTEREST'
9
- ACH_RECEIPT = 'ACH_RECEIPT'
10
- ACH_DISBURSEMENT = 'ACH_DISBURSEMENT'
11
- CASH_RECEIPT = 'CASH_RECEIPT'
12
- CASH_DISBURSEMENT = 'CASH_DISBURSEMENT'
13
- ELECTRONIC_FUND = 'ELECTRONIC_FUND'
14
- WIRE_OUT = 'WIRE_OUT'
15
- WIRE_IN = 'WIRE_IN'
16
- JOURNAL = 'JOURNAL'
17
- MEMORANDUM = 'MEMORANDUM'
18
- MARGIN_CALL = 'MARGIN_CALL'
19
- MONEY_MARKET = 'MONEY_MARKET'
20
- SMA_ADJUSTMENT = 'SMA_ADJUSTMENT'
6
+ TRADE = "TRADE"
7
+ RECEIVE_AND_DELIVER = "RECEIVE_AND_DELIVER"
8
+ DIVIDEND_OR_INTEREST = "DIVIDEND_OR_INTEREST"
9
+ ACH_RECEIPT = "ACH_RECEIPT"
10
+ ACH_DISBURSEMENT = "ACH_DISBURSEMENT"
11
+ CASH_RECEIPT = "CASH_RECEIPT"
12
+ CASH_DISBURSEMENT = "CASH_DISBURSEMENT"
13
+ ELECTRONIC_FUND = "ELECTRONIC_FUND"
14
+ WIRE_OUT = "WIRE_OUT"
15
+ WIRE_IN = "WIRE_IN"
16
+ JOURNAL = "JOURNAL"
17
+ MEMORANDUM = "MEMORANDUM"
18
+ MARGIN_CALL = "MARGIN_CALL"
19
+ MONEY_MARKET = "MONEY_MARKET"
20
+ SMA_ADJUSTMENT = "SMA_ADJUSTMENT"
21
21
  end
22
22
  end
23
23
  end
@@ -1,5 +1,5 @@
1
- require 'logger'
2
- require 'fileutils'
1
+ require "logger"
2
+ require "fileutils"
3
3
 
4
4
  module SchwabRb
5
5
  class Logger
@@ -27,17 +27,13 @@ module SchwabRb
27
27
 
28
28
  log_destination = config.effective_log_file || STDOUT
29
29
 
30
- if log_destination == :null || log_destination == '/dev/null'
31
- return null_logger
32
- end
30
+ return null_logger if [:null, "/dev/null"].include?(log_destination)
33
31
 
34
- if log_destination.is_a?(String) && log_destination != 'STDOUT'
35
- setup_log_file(log_destination)
36
- end
32
+ setup_log_file(log_destination) if log_destination.is_a?(String) && log_destination != "STDOUT"
37
33
 
38
- ::Logger.new(log_destination, 'weekly').tap do |log|
34
+ ::Logger.new(log_destination, "weekly").tap do |log|
39
35
  log.level = parse_log_level(config.log_level)
40
- log.formatter = proc do |severity, datetime, progname, msg|
36
+ log.formatter = proc do |severity, datetime, _progname, msg|
41
37
  "[#{datetime.strftime('%H:%M:%S')}] SCHWAB_RB #{severity}: #{msg}\n"
42
38
  end
43
39
  end
@@ -57,11 +53,11 @@ module SchwabRb
57
53
 
58
54
  def parse_log_level(level)
59
55
  case level.to_s.upcase
60
- when 'DEBUG' then ::Logger::DEBUG
61
- when 'INFO' then ::Logger::INFO
62
- when 'WARN' then ::Logger::WARN
63
- when 'ERROR' then ::Logger::ERROR
64
- when 'FATAL' then ::Logger::FATAL
56
+ when "DEBUG" then ::Logger::DEBUG
57
+ when "INFO" then ::Logger::INFO
58
+ when "WARN" then ::Logger::WARN
59
+ when "ERROR" then ::Logger::ERROR
60
+ when "FATAL" then ::Logger::FATAL
65
61
  else ::Logger::WARN
66
62
  end
67
63
  end
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'json'
3
+ require "json"
4
4
 
5
5
  module SchwabRb
6
6
  class Redactor
7
7
  # Patterns for account numbers and hashes that should be redacted
8
8
  ACCOUNT_NUMBER_PATTERN = /\b\d{8,12}\b/
9
9
  ACCOUNT_HASH_PATTERN = /\b[A-Z0-9]{32}\b/
10
-
10
+
11
11
  # JSON keys that commonly contain sensitive account information
12
12
  SENSITIVE_KEYS = %w[
13
13
  accountNumber
@@ -16,19 +16,19 @@ module SchwabRb
16
16
  hashValue
17
17
  encryptedId
18
18
  ].freeze
19
-
19
+
20
20
  def self.redact_url(url_string)
21
21
  return url_string unless url_string
22
-
22
+
23
23
  redacted = url_string.to_s.dup
24
- redacted.gsub!(ACCOUNT_NUMBER_PATTERN, '[REDACTED_ACCOUNT_NUMBER]')
25
- redacted.gsub!(ACCOUNT_HASH_PATTERN, '[REDACTED_ACCOUNT_HASH]')
24
+ redacted.gsub!(ACCOUNT_NUMBER_PATTERN, "[REDACTED_ACCOUNT_NUMBER]")
25
+ redacted.gsub!(ACCOUNT_HASH_PATTERN, "[REDACTED_ACCOUNT_HASH]")
26
26
  redacted
27
27
  end
28
-
28
+
29
29
  def self.redact_data(data)
30
30
  return data unless data
31
-
31
+
32
32
  case data
33
33
  when Hash
34
34
  redact_hash(data)
@@ -43,13 +43,13 @@ module SchwabRb
43
43
  data
44
44
  end
45
45
  end
46
-
46
+
47
47
  def self.redact_response_body(response)
48
48
  return unless response&.respond_to?(:body)
49
-
49
+
50
50
  body = response.body
51
51
  return unless body
52
-
52
+
53
53
  begin
54
54
  if body.is_a?(String)
55
55
  parsed = JSON.parse(body)
@@ -70,34 +70,32 @@ module SchwabRb
70
70
  redact_string(body_str)
71
71
  end
72
72
  end
73
-
74
- private
75
-
73
+
76
74
  def self.redact_hash(hash)
77
75
  hash.each_with_object({}) do |(key, value), redacted|
78
- if SENSITIVE_KEYS.include?(key.to_s)
79
- redacted[key] = '[REDACTED]'
76
+ redacted[key] = if SENSITIVE_KEYS.include?(key.to_s)
77
+ "[REDACTED]"
80
78
  else
81
79
  case value
82
80
  when Hash
83
- redacted[key] = redact_hash(value)
81
+ redact_hash(value)
84
82
  when Array
85
- redacted[key] = value.map { |item| redact_data(item) }
83
+ value.map { |item| redact_data(item) }
86
84
  when String
87
- redacted[key] = redact_string(value)
85
+ redact_string(value)
88
86
  else
89
- redacted[key] = value
87
+ value
90
88
  end
91
- end
89
+ end
92
90
  end
93
91
  end
94
-
92
+
95
93
  def self.redact_string(str)
96
94
  return str unless str.is_a?(String)
97
-
95
+
98
96
  redacted = str.dup
99
- redacted.gsub!(ACCOUNT_NUMBER_PATTERN, '[REDACTED_ACCOUNT_NUMBER]')
100
- redacted.gsub!(ACCOUNT_HASH_PATTERN, '[REDACTED_ACCOUNT_HASH]')
97
+ redacted.gsub!(ACCOUNT_NUMBER_PATTERN, "[REDACTED_ACCOUNT_NUMBER]")
98
+ redacted.gsub!(ACCOUNT_HASH_PATTERN, "[REDACTED_ACCOUNT_HASH]")
101
99
  redacted
102
100
  end
103
101
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SchwabRb
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/schwab_rb.rb CHANGED
@@ -42,6 +42,7 @@ require_relative "schwab_rb/data_objects/option_chain"
42
42
  require_relative "schwab_rb/data_objects/option_expiration_chain"
43
43
  require_relative "schwab_rb/data_objects/price_history"
44
44
  require_relative "schwab_rb/data_objects/market_hours"
45
+ require_relative "schwab_rb/data_objects/market_movers"
45
46
 
46
47
  module SchwabRb
47
48
  class Error < StandardError; end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: schwab_rb
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
  - Joseph Platta
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-07-20 00:00:00.000000000 Z
10
+ date: 2025-07-21 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: async
@@ -192,12 +192,14 @@ executables: []
192
192
  extensions: []
193
193
  extra_rdoc_files: []
194
194
  files:
195
+ - ".claude/settings.local.json"
195
196
  - ".copilotignore"
196
197
  - ".rspec"
197
198
  - ".rspec_status"
198
199
  - ".rubocop.yml"
199
200
  - ".rubocop_todo.yml"
200
201
  - CHANGELOG.md
202
+ - CLAUDE.md
201
203
  - LICENSE.txt
202
204
  - README.md
203
205
  - Rakefile
@@ -223,6 +225,7 @@ files:
223
225
  - lib/schwab_rb/data_objects/account_numbers.rb
224
226
  - lib/schwab_rb/data_objects/instrument.rb
225
227
  - lib/schwab_rb/data_objects/market_hours.rb
228
+ - lib/schwab_rb/data_objects/market_movers.rb
226
229
  - lib/schwab_rb/data_objects/option.rb
227
230
  - lib/schwab_rb/data_objects/option_chain.rb
228
231
  - lib/schwab_rb/data_objects/option_expiration_chain.rb
@@ -269,6 +272,7 @@ metadata:
269
272
  homepage_uri: https://github.com/jwplatta/schwab_rb
270
273
  source_code_uri: https://github.com/jwplatta/schwab_rb
271
274
  changelog_uri: https://github.com/jwplatta/schwab_rb/blob/main/CHANGELOG.md
275
+ rubygems_mfa_required: 'true'
272
276
  rdoc_options: []
273
277
  require_paths:
274
278
  - lib