schwab_rb 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 +7 -0
- data/.copilotignore +4 -0
- data/.rspec +2 -0
- data/.rspec_status +292 -0
- data/.rubocop.yml +41 -0
- data/.rubocop_todo.yml +105 -0
- data/CHANGELOG.md +28 -0
- data/LICENSE.txt +23 -0
- data/README.md +271 -0
- data/Rakefile +12 -0
- data/doc/notes/data_objects_analysis.md +223 -0
- data/doc/notes/data_objects_refactoring_plan.md +82 -0
- data/examples/fetch_account_numbers.rb +49 -0
- data/examples/fetch_user_preferences.rb +49 -0
- data/lib/schwab_rb/account.rb +9 -0
- data/lib/schwab_rb/auth/auth_context.rb +23 -0
- data/lib/schwab_rb/auth/init_client_easy.rb +45 -0
- data/lib/schwab_rb/auth/init_client_login.rb +201 -0
- data/lib/schwab_rb/auth/init_client_token_file.rb +30 -0
- data/lib/schwab_rb/auth/login_flow_server.rb +55 -0
- data/lib/schwab_rb/auth/token.rb +24 -0
- data/lib/schwab_rb/auth/token_manager.rb +105 -0
- data/lib/schwab_rb/clients/async_client.rb +122 -0
- data/lib/schwab_rb/clients/base_client.rb +887 -0
- data/lib/schwab_rb/clients/client.rb +97 -0
- data/lib/schwab_rb/configuration.rb +39 -0
- data/lib/schwab_rb/constants.rb +7 -0
- data/lib/schwab_rb/data_objects/account.rb +281 -0
- data/lib/schwab_rb/data_objects/account_numbers.rb +68 -0
- data/lib/schwab_rb/data_objects/instrument.rb +156 -0
- data/lib/schwab_rb/data_objects/market_hours.rb +275 -0
- data/lib/schwab_rb/data_objects/option.rb +147 -0
- data/lib/schwab_rb/data_objects/option_chain.rb +95 -0
- data/lib/schwab_rb/data_objects/option_expiration_chain.rb +134 -0
- data/lib/schwab_rb/data_objects/order.rb +186 -0
- data/lib/schwab_rb/data_objects/order_leg.rb +68 -0
- data/lib/schwab_rb/data_objects/order_preview.rb +237 -0
- data/lib/schwab_rb/data_objects/position.rb +100 -0
- data/lib/schwab_rb/data_objects/price_history.rb +187 -0
- data/lib/schwab_rb/data_objects/quote.rb +276 -0
- data/lib/schwab_rb/data_objects/transaction.rb +132 -0
- data/lib/schwab_rb/data_objects/user_preferences.rb +129 -0
- data/lib/schwab_rb/market_hours.rb +13 -0
- data/lib/schwab_rb/movers.rb +35 -0
- data/lib/schwab_rb/option.rb +64 -0
- data/lib/schwab_rb/orders/builder.rb +202 -0
- data/lib/schwab_rb/orders/destination.rb +19 -0
- data/lib/schwab_rb/orders/duration.rb +9 -0
- data/lib/schwab_rb/orders/equity_instructions.rb +10 -0
- data/lib/schwab_rb/orders/errors.rb +5 -0
- data/lib/schwab_rb/orders/instruments.rb +35 -0
- data/lib/schwab_rb/orders/option_instructions.rb +10 -0
- data/lib/schwab_rb/orders/order.rb +77 -0
- data/lib/schwab_rb/orders/price_link_basis.rb +15 -0
- data/lib/schwab_rb/orders/price_link_type.rb +9 -0
- data/lib/schwab_rb/orders/session.rb +14 -0
- data/lib/schwab_rb/orders/special_instruction.rb +10 -0
- data/lib/schwab_rb/orders/stop_price_link_basis.rb +15 -0
- data/lib/schwab_rb/orders/stop_price_link_type.rb +9 -0
- data/lib/schwab_rb/orders/stop_type.rb +11 -0
- data/lib/schwab_rb/orders/tax_lot_method.rb +13 -0
- data/lib/schwab_rb/price_history.rb +55 -0
- data/lib/schwab_rb/quote.rb +13 -0
- data/lib/schwab_rb/transaction.rb +23 -0
- data/lib/schwab_rb/utils/enum_enforcer.rb +73 -0
- data/lib/schwab_rb/utils/logger.rb +70 -0
- data/lib/schwab_rb/utils/redactor.rb +104 -0
- data/lib/schwab_rb/version.rb +5 -0
- data/lib/schwab_rb.rb +48 -0
- data/sig/schwab_rb.rbs +4 -0
- metadata +289 -0
@@ -0,0 +1,187 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SchwabRb
|
4
|
+
module DataObjects
|
5
|
+
class PriceHistory
|
6
|
+
attr_reader :symbol, :empty, :candles
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def build(data)
|
10
|
+
new(data)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(data)
|
15
|
+
@symbol = data['symbol']
|
16
|
+
@empty = data['empty']
|
17
|
+
@candles = data['candles']&.map { |candle_data| Candle.new(candle_data) } || []
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_h
|
21
|
+
{
|
22
|
+
'symbol' => @symbol,
|
23
|
+
'empty' => @empty,
|
24
|
+
'candles' => @candles.map(&:to_h)
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
def empty?
|
29
|
+
@empty == true || @candles.empty?
|
30
|
+
end
|
31
|
+
|
32
|
+
def count
|
33
|
+
@candles.length
|
34
|
+
end
|
35
|
+
alias size count
|
36
|
+
alias length count
|
37
|
+
|
38
|
+
def first_candle
|
39
|
+
@candles.first
|
40
|
+
end
|
41
|
+
|
42
|
+
def last_candle
|
43
|
+
@candles.last
|
44
|
+
end
|
45
|
+
|
46
|
+
def candles_for_date_range(start_date, end_date)
|
47
|
+
start_timestamp = start_date.to_time.to_i * 1000
|
48
|
+
end_timestamp = end_date.to_time.to_i * 1000
|
49
|
+
|
50
|
+
@candles.select do |candle|
|
51
|
+
candle.datetime >= start_timestamp && candle.datetime <= end_timestamp
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def highest_price
|
56
|
+
return nil if @candles.empty?
|
57
|
+
@candles.map(&:high).max
|
58
|
+
end
|
59
|
+
|
60
|
+
def lowest_price
|
61
|
+
return nil if @candles.empty?
|
62
|
+
@candles.map(&:low).min
|
63
|
+
end
|
64
|
+
|
65
|
+
def highest_volume
|
66
|
+
return nil if @candles.empty?
|
67
|
+
@candles.map(&:volume).max
|
68
|
+
end
|
69
|
+
|
70
|
+
def total_volume
|
71
|
+
return 0 if @candles.empty?
|
72
|
+
@candles.map(&:volume).sum
|
73
|
+
end
|
74
|
+
|
75
|
+
def average_price
|
76
|
+
return nil if @candles.empty?
|
77
|
+
total_price = @candles.map(&:close).sum
|
78
|
+
total_price / @candles.length.to_f
|
79
|
+
end
|
80
|
+
|
81
|
+
def price_range
|
82
|
+
return nil if @candles.empty?
|
83
|
+
{
|
84
|
+
high: highest_price,
|
85
|
+
low: lowest_price,
|
86
|
+
range: highest_price - lowest_price
|
87
|
+
}
|
88
|
+
end
|
89
|
+
|
90
|
+
def each(&block)
|
91
|
+
return enum_for(:each) unless block_given?
|
92
|
+
@candles.each(&block)
|
93
|
+
end
|
94
|
+
|
95
|
+
include Enumerable
|
96
|
+
|
97
|
+
class Candle
|
98
|
+
attr_reader :open, :high, :low, :close, :volume, :datetime
|
99
|
+
|
100
|
+
def initialize(data)
|
101
|
+
@open = data['open']
|
102
|
+
@high = data['high']
|
103
|
+
@low = data['low']
|
104
|
+
@close = data['close']
|
105
|
+
@volume = data['volume']
|
106
|
+
@datetime = data['datetime']
|
107
|
+
end
|
108
|
+
|
109
|
+
def to_h
|
110
|
+
{
|
111
|
+
'open' => @open,
|
112
|
+
'high' => @high,
|
113
|
+
'low' => @low,
|
114
|
+
'close' => @close,
|
115
|
+
'volume' => @volume,
|
116
|
+
'datetime' => @datetime
|
117
|
+
}
|
118
|
+
end
|
119
|
+
|
120
|
+
def date_time
|
121
|
+
Time.at(@datetime / 1000.0) if @datetime
|
122
|
+
end
|
123
|
+
|
124
|
+
def date
|
125
|
+
date_time&.to_date
|
126
|
+
end
|
127
|
+
|
128
|
+
def price_change
|
129
|
+
@close - @open
|
130
|
+
end
|
131
|
+
|
132
|
+
def price_change_percent
|
133
|
+
return 0 if @open == 0
|
134
|
+
((price_change / @open) * 100).round(4)
|
135
|
+
end
|
136
|
+
|
137
|
+
def is_green?
|
138
|
+
@close > @open
|
139
|
+
end
|
140
|
+
|
141
|
+
def is_red?
|
142
|
+
@close < @open
|
143
|
+
end
|
144
|
+
|
145
|
+
def is_doji?
|
146
|
+
@close == @open
|
147
|
+
end
|
148
|
+
|
149
|
+
def body_size
|
150
|
+
(@close - @open).abs
|
151
|
+
end
|
152
|
+
|
153
|
+
def wick_size
|
154
|
+
upper_wick + lower_wick
|
155
|
+
end
|
156
|
+
|
157
|
+
def upper_wick
|
158
|
+
@high - [@open, @close].max
|
159
|
+
end
|
160
|
+
|
161
|
+
def lower_wick
|
162
|
+
[@open, @close].min - @low
|
163
|
+
end
|
164
|
+
|
165
|
+
def true_range
|
166
|
+
[
|
167
|
+
@high - @low,
|
168
|
+
(@high - @close).abs,
|
169
|
+
(@low - @close).abs
|
170
|
+
].max
|
171
|
+
end
|
172
|
+
|
173
|
+
def ohlc_average
|
174
|
+
(@open + @high + @low + @close) / 4.0
|
175
|
+
end
|
176
|
+
|
177
|
+
def typical_price
|
178
|
+
(@high + @low + @close) / 3.0
|
179
|
+
end
|
180
|
+
|
181
|
+
def weighted_price
|
182
|
+
(@high + @low + @close + @close) / 4.0
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
@@ -0,0 +1,276 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module SchwabRb
|
4
|
+
module DataObjects
|
5
|
+
class QuoteFactory
|
6
|
+
def self.build(quote_data)
|
7
|
+
# Extract the data from nested structure (symbol is the key)
|
8
|
+
symbol = quote_data.keys.first
|
9
|
+
data = quote_data[symbol]
|
10
|
+
data[:symbol] ||= symbol
|
11
|
+
|
12
|
+
case data[:assetMainType]
|
13
|
+
when 'OPTION'
|
14
|
+
OptionQuote.new(data)
|
15
|
+
when 'INDEX'
|
16
|
+
IndexQuote.new(data)
|
17
|
+
when 'EQUITY'
|
18
|
+
EquityQuote.new(data)
|
19
|
+
else
|
20
|
+
raise "Unknown assetMainType: #{data[:assetMainType]}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class OptionQuote
|
26
|
+
attr_reader :symbol, :asset_main_type, :realtime, :ssid, :quote_52_week_high, :quote_52_week_low, :ask_price,
|
27
|
+
:ask_size, :bid_price, :bid_size, :close_price, :delta, :gamma, :high_price, :ind_ask_price, :ind_bid_price, :ind_time, :implied_yield, :last_price, :last_size, :low_price, :mark, :mark_change, :mark_percent_change, :money_intrinsic_value, :net_change, :net_percent_change, :open_interest, :open_price, :time, :rho, :security_status, :theoretical_option_value, :theta, :time_value, :total_volume, :trade_time, :underlying_price, :vega, :volatility, :contract_type, :days_to_expiration, :deliverables, :description, :exchange, :exchange_name, :exercise_type, :expiration_day, :expiration_month, :expiration_type, :expiration_year, :is_penny_pilot, :last_trading_day, :multiplier, :settlement_type, :strike_price, :underlying, :underlying_asset_type
|
28
|
+
|
29
|
+
def initialize(data)
|
30
|
+
@symbol = data[:symbol]
|
31
|
+
@asset_main_type = data[:assetMainType]
|
32
|
+
@realtime = data[:realtime]
|
33
|
+
@ssid = data[:ssid]
|
34
|
+
@quote_52_week_high = data.dig(:quote, :"52WeekHigh")
|
35
|
+
@quote_52_week_low = data.dig(:quote, :"52WeekLow")
|
36
|
+
@ask_price = data.dig(:quote, :askPrice)
|
37
|
+
@ask_size = data.dig(:quote, :askSize)
|
38
|
+
@bid_price = data.dig(:quote, :bidPrice)
|
39
|
+
@bid_size = data.dig(:quote, :bidSize)
|
40
|
+
@close_price = data.dig(:quote, :closePrice)
|
41
|
+
@delta = data.dig(:quote, :delta)
|
42
|
+
@gamma = data.dig(:quote, :gamma)
|
43
|
+
@high_price = data.dig(:quote, :highPrice)
|
44
|
+
@ind_ask_price = data.dig(:quote, :indAskPrice)
|
45
|
+
@ind_bid_price = data.dig(:quote, :indBidPrice)
|
46
|
+
@ind_quote_time = data.dig(:quote, :indQuoteTime)
|
47
|
+
@implied_yield = data.dig(:quote, :impliedYield)
|
48
|
+
@last_price = data.dig(:quote, :lastPrice)
|
49
|
+
@last_size = data.dig(:quote, :lastSize)
|
50
|
+
@low_price = data.dig(:quote, :lowPrice)
|
51
|
+
@mark = data.dig(:quote, :mark)
|
52
|
+
@mark_change = data.dig(:quote, :markChange)
|
53
|
+
@mark_percent_change = data.dig(:quote, :markPercentChange)
|
54
|
+
@money_intrinsic_value = data.dig(:quote, :moneyIntrinsicValue)
|
55
|
+
@net_change = data.dig(:quote, :netChange)
|
56
|
+
@net_percent_change = data.dig(:quote, :netPercentChange)
|
57
|
+
@open_interest = data.dig(:quote, :openInterest)
|
58
|
+
@open_price = data.dig(:quote, :openPrice)
|
59
|
+
@quote_time = data.dig(:quote, :quoteTime)
|
60
|
+
@rho = data.dig(:quote, :rho)
|
61
|
+
@security_status = data.dig(:quote, :securityStatus)
|
62
|
+
@theoretical_option_value = data.dig(:quote, :theoreticalOptionValue)
|
63
|
+
@theta = data.dig(:quote, :theta)
|
64
|
+
@time_value = data.dig(:quote, :timeValue)
|
65
|
+
@total_volume = data.dig(:quote, :totalVolume)
|
66
|
+
@trade_time = data.dig(:quote, :tradeTime)
|
67
|
+
@underlying_price = data.dig(:quote, :underlyingPrice)
|
68
|
+
@vega = data.dig(:quote, :vega)
|
69
|
+
@volatility = data.dig(:quote, :volatility)
|
70
|
+
@contract_type = data.dig(:reference, :contractType)
|
71
|
+
@days_to_expiration = data.dig(:reference, :daysToExpiration)
|
72
|
+
@deliverables = data.dig(:reference, :deliverables)
|
73
|
+
@description = data.dig(:reference, :description)
|
74
|
+
@exchange = data.dig(:reference, :exchange)
|
75
|
+
@exchange_name = data.dig(:reference, :exchangeName)
|
76
|
+
@exercise_type = data.dig(:reference, :exerciseType)
|
77
|
+
@expiration_day = data.dig(:reference, :expirationDay)
|
78
|
+
@expiration_month = data.dig(:reference, :expirationMonth)
|
79
|
+
@expiration_type = data.dig(:reference, :expirationType)
|
80
|
+
@expiration_year = data.dig(:reference, :expirationYear)
|
81
|
+
@is_penny_pilot = data.dig(:reference, :isPennyPilot)
|
82
|
+
@last_trading_day = data.dig(:reference, :lastTradingDay)
|
83
|
+
@multiplier = data.dig(:reference, :multiplier)
|
84
|
+
@settlement_type = data.dig(:reference, :settlementType)
|
85
|
+
@strike_price = data.dig(:reference, :strikePrice)
|
86
|
+
@underlying = data.dig(:reference, :underlying)
|
87
|
+
@underlying_asset_type = data.dig(:reference, :underlyingAssetType)
|
88
|
+
end
|
89
|
+
|
90
|
+
def zone
|
91
|
+
if quote_delta.abs > 0.3
|
92
|
+
'DANGER'
|
93
|
+
elsif quote_delta.abs > 0.15
|
94
|
+
'AT_RISK'
|
95
|
+
else
|
96
|
+
'SAFE'
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class IndexQuote
|
102
|
+
attr_reader :symbol, :asset_main_type, :realtime, :ssid, :avg_10_days_volume, :avg_1_year_volume, :div_amount,
|
103
|
+
:div_freq, :div_pay_amount, :div_yield, :eps, :fund_leverage_factor, :pe_ratio, :quote_52_week_high, :quote_52_week_low, :close_price, :high_price, :last_price, :low_price, :net_change, :net_percent_change, :open_price, :security_status, :total_volume, :trade_time, :description, :exchange, :exchange_name
|
104
|
+
|
105
|
+
def initialize(data)
|
106
|
+
@symbol = data[:symbol]
|
107
|
+
@asset_main_type = data[:assetMainType]
|
108
|
+
@realtime = data[:realtime]
|
109
|
+
@ssid = data[:ssid]
|
110
|
+
@avg_10_days_volume = data.dig(:fundamental, :avg10DaysVolume)
|
111
|
+
@avg_1_year_volume = data.dig(:fundamental, :avg1YearVolume)
|
112
|
+
@div_amount = data.dig(:fundamental, :divAmount)
|
113
|
+
@div_freq = data.dig(:fundamental, :divFreq)
|
114
|
+
@div_pay_amount = data.dig(:fundamental, :divPayAmount)
|
115
|
+
@div_yield = data.dig(:fundamental, :divYield)
|
116
|
+
@eps = data.dig(:fundamental, :eps)
|
117
|
+
@fund_leverage_factor = data.dig(:fundamental, :fundLeverageFactor)
|
118
|
+
@pe_ratio = data.dig(:fundamental, :peRatio)
|
119
|
+
@quote_52_week_high = data.dig(:quote, :"52WeekHigh")
|
120
|
+
@quote_52_week_low = data.dig(:quote, :"52WeekLow")
|
121
|
+
@close_price = data.dig(:quote, :closePrice)
|
122
|
+
@high_price = data.dig(:quote, :highPrice)
|
123
|
+
@last_price = data.dig(:quote, :lastPrice)
|
124
|
+
@low_price = data.dig(:quote, :lowPrice)
|
125
|
+
@net_change = data.dig(:quote, :netChange)
|
126
|
+
@net_percent_change = data.dig(:quote, :netPercentChange)
|
127
|
+
@open_price = data.dig(:quote, :openPrice)
|
128
|
+
@security_status = data.dig(:quote, :securityStatus)
|
129
|
+
@total_volume = data.dig(:quote, :totalVolume)
|
130
|
+
@trade_time = data.dig(:quote, :tradeTime)
|
131
|
+
@description = data.dig(:reference, :description)
|
132
|
+
@exchange = data.dig(:reference, :exchange)
|
133
|
+
@exchange_name = data.dig(:reference, :exchangeName)
|
134
|
+
end
|
135
|
+
|
136
|
+
def mark
|
137
|
+
(@high_price + @low_price) / 2.0
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class EquityQuote
|
142
|
+
attr_reader :symbol, :asset_main_type, :asset_sub_type, :quote_type, :realtime, :ssid, :extended_ask_price,
|
143
|
+
:extended_ask_size, :extended_bid_price, :extended_bid_size, :extended_last_price, :extended_last_size, :extended_mark, :extended_quote_time, :extended_total_volume, :extended_trade_time, :avg_10_days_volume, :avg_1_year_volume, :declaration_date, :div_amount, :div_ex_date, :div_freq, :div_pay_amount, :div_pay_date, :div_yield, :eps, :fund_leverage_factor, :last_earnings_date, :next_div_ex_date, :next_div_pay_date, :pe_ratio, :quote_52_week_high, :quote_52_week_low, :ask_mic_id, :ask_price, :ask_size, :ask_time, :bid_mic_id, :bid_price, :bid_size, :bid_time, :close_price, :high_price, :last_mic_id, :last_price, :last_size, :low_price, :mark, :mark_change, :mark_percent_change, :net_change, :net_percent_change, :open_price, :post_market_change, :post_market_percent_change, :time, :security_status, :total_volume, :trade_time, :cusip, :description, :exchange, :exchange_name, :is_hard_to_borrow, :is_shortable, :htb_rate, :market_last_price, :market_last_size, :market_net_change, :market_percent_change, :market_trade_time
|
144
|
+
|
145
|
+
def initialize(data)
|
146
|
+
@symbol = data[:symbol]
|
147
|
+
@asset_main_type = data[:assetMainType]
|
148
|
+
@asset_sub_type = data[:assetSubType]
|
149
|
+
@quote_type = data[:quoteType]
|
150
|
+
@realtime = data[:realtime]
|
151
|
+
@ssid = data[:ssid]
|
152
|
+
@extended_ask_price = data.dig(:extended, :askPrice)
|
153
|
+
@extended_ask_size = data.dig(:extended, :askSize)
|
154
|
+
@extended_bid_price = data.dig(:extended, :bidPrice)
|
155
|
+
@extended_bid_size = data.dig(:extended, :bidSize)
|
156
|
+
@extended_last_price = data.dig(:extended, :lastPrice)
|
157
|
+
@extended_last_size = data.dig(:extended, :lastSize)
|
158
|
+
@extended_mark = data.dig(:extended, :mark)
|
159
|
+
@extended_quote_time = data.dig(:extended, :quoteTime)
|
160
|
+
@extended_total_volume = data.dig(:extended, :totalVolume)
|
161
|
+
@extended_trade_time = data.dig(:extended, :tradeTime)
|
162
|
+
@avg_10_days_volume = data.dig(:fundamental, :avg10DaysVolume)
|
163
|
+
@avg_1_year_volume = data.dig(:fundamental, :avg1YearVolume)
|
164
|
+
@declaration_date = data.dig(:fundamental, :declarationDate)
|
165
|
+
@div_amount = data.dig(:fundamental, :divAmount)
|
166
|
+
@div_ex_date = data.dig(:fundamental, :divExDate)
|
167
|
+
@div_freq = data.dig(:fundamental, :divFreq)
|
168
|
+
@div_pay_amount = data.dig(:fundamental, :divPayAmount)
|
169
|
+
@div_pay_date = data.dig(:fundamental, :divPayDate)
|
170
|
+
@div_yield = data.dig(:fundamental, :divYield)
|
171
|
+
@eps = data.dig(:fundamental, :eps)
|
172
|
+
@fund_leverage_factor = data.dig(:fundamental, :fundLeverageFactor)
|
173
|
+
@last_earnings_date = data.dig(:fundamental, :lastEarningsDate)
|
174
|
+
@next_div_ex_date = data.dig(:fundamental, :nextDivExDate)
|
175
|
+
@next_div_pay_date = data.dig(:fundamental, :nextDivPayDate)
|
176
|
+
@pe_ratio = data.dig(:fundamental, :peRatio)
|
177
|
+
@quote_52_week_high = data.dig(:quote, :"52WeekHigh")
|
178
|
+
@quote_52_week_low = data.dig(:quote, :"52WeekLow")
|
179
|
+
@ask_mic_id = data.dig(:quote, :askMICId)
|
180
|
+
@ask_price = data.dig(:quote, :askPrice)
|
181
|
+
@ask_size = data.dig(:quote, :askSize)
|
182
|
+
@ask_time = data.dig(:quote, :askTime)
|
183
|
+
@bid_mic_id = data.dig(:quote, :bidMICId)
|
184
|
+
@bid_price = data.dig(:quote, :bidPrice)
|
185
|
+
@bid_size = data.dig(:quote, :bidSize)
|
186
|
+
@bid_time = data.dig(:quote, :bidTime)
|
187
|
+
@close_price = data.dig(:quote, :closePrice)
|
188
|
+
@high_price = data.dig(:quote, :highPrice)
|
189
|
+
@last_mic_id = data.dig(:quote, :lastMICId)
|
190
|
+
@last_price = data.dig(:quote, :lastPrice)
|
191
|
+
@last_size = data.dig(:quote, :lastSize)
|
192
|
+
@low_price = data.dig(:quote, :lowPrice)
|
193
|
+
@mark = data.dig(:quote, :mark)
|
194
|
+
@mark_change = data.dig(:quote, :markChange)
|
195
|
+
@mark_percent_change = data.dig(:quote, :markPercentChange)
|
196
|
+
@net_change = data.dig(:quote, :netChange)
|
197
|
+
@net_percent_change = data.dig(:quote, :netPercentChange)
|
198
|
+
@open_price = data.dig(:quote, :openPrice)
|
199
|
+
@post_market_change = data.dig(:quote, :postMarketChange)
|
200
|
+
@post_market_percent_change = data.dig(:quote, :postMarketPercentChange)
|
201
|
+
@quote_time = data.dig(:quote, :quoteTime)
|
202
|
+
@security_status = data.dig(:quote, :securityStatus)
|
203
|
+
@total_volume = data.dig(:quote, :totalVolume)
|
204
|
+
@trade_time = data.dig(:quote, :tradeTime)
|
205
|
+
@cusip = data.dig(:reference, :cusip)
|
206
|
+
@description = data.dig(:reference, :description)
|
207
|
+
@exchange = data.dig(:reference, :exchange)
|
208
|
+
@exchange_name = data.dig(:reference, :exchangeName)
|
209
|
+
@is_hard_to_borrow = data.dig(:reference, :isHardToBorrow)
|
210
|
+
@is_shortable = data.dig(:reference, :isShortable)
|
211
|
+
@htb_rate = data.dig(:reference, :htbRate)
|
212
|
+
@market_last_price = data.dig(:regular, :regularMarketLastPrice)
|
213
|
+
@market_last_size = data.dig(:regular, :regularMarketLastSize)
|
214
|
+
@market_net_change = data.dig(:regular, :regularMarketNetChange)
|
215
|
+
@market_percent_change = data.dig(:regular, :regularMarketPercentChange)
|
216
|
+
@market_trade_time = data.dig(:regular, :regularMarketTradeTime)
|
217
|
+
end
|
218
|
+
|
219
|
+
def to_h
|
220
|
+
{
|
221
|
+
symbol: @symbol,
|
222
|
+
asset_main_type: @asset_main_type,
|
223
|
+
asset_sub_type: @asset_sub_type,
|
224
|
+
quote_type: @quote_type,
|
225
|
+
realtime: @realtime,
|
226
|
+
ssid: @ssid,
|
227
|
+
extended_ask_price: @extended_ask_price,
|
228
|
+
extended_ask_size: @extended_ask_size,
|
229
|
+
extended_bid_price: @extended_bid_price,
|
230
|
+
extended_bid_size: @extended_bid_size,
|
231
|
+
extended_last_price: @extended_last_price,
|
232
|
+
extended_last_size: @extended_last_size,
|
233
|
+
extended_mark: @extended_mark,
|
234
|
+
extended_quote_time: @extended_quote_time,
|
235
|
+
extended_total_volume: @extended_total_volume,
|
236
|
+
extended_trade_time: @extended_trade_time,
|
237
|
+
avg_10_days_volume: @avg_10_days_volume,
|
238
|
+
avg_1_year_volume: @avg_1_year_volume,
|
239
|
+
declaration_date: @declaration_date,
|
240
|
+
div_amount: @div_amount,
|
241
|
+
div_ex_date: @div_ex_date,
|
242
|
+
div_freq: @div_freq,
|
243
|
+
div_pay_amount: @div_pay_amount,
|
244
|
+
div_pay_date: @div_pay_date,
|
245
|
+
div_yield: @div_yield,
|
246
|
+
eps: @eps,
|
247
|
+
fund_leverage_factor: @fund_leverage_factor,
|
248
|
+
last_earnings_date: @last_earnings_date,
|
249
|
+
next_div_ex_date: @next_div_ex_date,
|
250
|
+
next_div_pay_date: @next_div_pay_date,
|
251
|
+
pe_ratio: @pe_ratio,
|
252
|
+
quote_52_week_high: @quote_52_week_high,
|
253
|
+
quote_52_week_low: @quote_52_week_low,
|
254
|
+
ask_mic_id: @ask_mic_id,
|
255
|
+
ask_price: @ask_price,
|
256
|
+
ask_size: @ask_size,
|
257
|
+
ask_time: @ask_time,
|
258
|
+
bid_mic_id: @bid_mic_id,
|
259
|
+
bid_price: @bid_price,
|
260
|
+
bid_size: @bid_size,
|
261
|
+
bid_time: @bid_time,
|
262
|
+
close_price: @close_price,
|
263
|
+
high_price: @high_price,
|
264
|
+
last_mic_id: @last_mic_id,
|
265
|
+
last_price: @last_price,
|
266
|
+
last_size: @last_size,
|
267
|
+
low_price: @low_price
|
268
|
+
}
|
269
|
+
end
|
270
|
+
|
271
|
+
def to_s
|
272
|
+
"<EquityQuote symbol: #{@symbol}, last_price: #{@last_price}, mark: #{@mark}, market_last_price: #{@market_last_price}, extended_bid_price: #{@extended_bid_price}>"
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'instrument'
|
4
|
+
|
5
|
+
module SchwabRb
|
6
|
+
module DataObjects
|
7
|
+
class TransferItem
|
8
|
+
class << self
|
9
|
+
def build(data)
|
10
|
+
TransferItem.new(
|
11
|
+
instrument: Instrument.build(data.fetch(:instrument)),
|
12
|
+
amount: data.fetch(:amount),
|
13
|
+
cost: data.fetch(:cost),
|
14
|
+
fee_type: data.fetch(:feeType, nil),
|
15
|
+
position_effect: data.fetch(:positionEffect, nil)
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :instrument, :amount, :cost, :fee_type, :position_effect
|
21
|
+
|
22
|
+
def initialize(instrument:, amount:, cost:, fee_type:, position_effect:)
|
23
|
+
@instrument = instrument
|
24
|
+
@amount = amount
|
25
|
+
@cost = cost
|
26
|
+
@fee_type = fee_type
|
27
|
+
@position_effect = position_effect
|
28
|
+
end
|
29
|
+
|
30
|
+
def symbol
|
31
|
+
option? ? instrument.symbol : ''
|
32
|
+
end
|
33
|
+
|
34
|
+
def underlying_symbol
|
35
|
+
option? ? instrument.underlying_symbol : ''
|
36
|
+
end
|
37
|
+
|
38
|
+
def description
|
39
|
+
option? ? instrument.description : ''
|
40
|
+
end
|
41
|
+
|
42
|
+
def option?
|
43
|
+
instrument.option?
|
44
|
+
end
|
45
|
+
|
46
|
+
def put_call
|
47
|
+
instrument.put_call
|
48
|
+
end
|
49
|
+
|
50
|
+
def fee?
|
51
|
+
%w[OPT_REG_FEE TAF_FEE SEC_FEE].include?(fee_type)
|
52
|
+
end
|
53
|
+
|
54
|
+
def commission?
|
55
|
+
fee_type == 'COMMISSION'
|
56
|
+
end
|
57
|
+
|
58
|
+
def to_h
|
59
|
+
{
|
60
|
+
instrument: instrument.to_h,
|
61
|
+
amount: amount,
|
62
|
+
cost: cost,
|
63
|
+
fee_type: fee_type,
|
64
|
+
position_effect: position_effect
|
65
|
+
}
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class Transaction
|
70
|
+
class << self
|
71
|
+
def build(data)
|
72
|
+
Transaction.new(
|
73
|
+
activity_id: data.fetch(:activityId),
|
74
|
+
time: data.fetch(:time),
|
75
|
+
type: data.fetch(:type),
|
76
|
+
status: data.fetch(:status),
|
77
|
+
sub_account: data.fetch(:subAccount),
|
78
|
+
trade_date: data.fetch(:tradeDate),
|
79
|
+
position_id: data.fetch(:positionId, nil),
|
80
|
+
order_id: data.fetch(:orderId, nil),
|
81
|
+
net_amount: data.fetch(:netAmount, nil),
|
82
|
+
transfer_items: data.fetch(:transferItems).map { |ti| TransferItem.build(ti) }
|
83
|
+
)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def initialize(activity_id:, time:, type:, status:, sub_account:, trade_date:, position_id:, order_id:,
|
88
|
+
net_amount:, transfer_items: [])
|
89
|
+
@activity_id = activity_id
|
90
|
+
@time = time
|
91
|
+
@type = type
|
92
|
+
@status = status
|
93
|
+
@sub_account = sub_account
|
94
|
+
@trade_date = trade_date
|
95
|
+
@position_id = position_id
|
96
|
+
@order_id = order_id
|
97
|
+
@net_amount = net_amount
|
98
|
+
@transfer_items = transfer_items
|
99
|
+
end
|
100
|
+
|
101
|
+
attr_reader :activity_id, :time, :type, :status, :sub_account, :trade_date, :position_id, :order_id, :net_amount,
|
102
|
+
:transfer_items
|
103
|
+
|
104
|
+
def trade?
|
105
|
+
type == 'TRADE'
|
106
|
+
end
|
107
|
+
|
108
|
+
def symbols
|
109
|
+
transfer_items.map { |ti| ti.instrument.symbol }
|
110
|
+
end
|
111
|
+
|
112
|
+
def option_symbol
|
113
|
+
transfer_items.find { |ti| ti.instrument.option? }.instrument.symbol
|
114
|
+
end
|
115
|
+
|
116
|
+
def to_h
|
117
|
+
{
|
118
|
+
activity_id: @activity_id,
|
119
|
+
time: @time,
|
120
|
+
type: @type,
|
121
|
+
status: @status,
|
122
|
+
sub_account: @sub_account,
|
123
|
+
trade_date: @trade_date,
|
124
|
+
position_id: @position_id,
|
125
|
+
order_id: @order_id,
|
126
|
+
net_amount: @net_amount,
|
127
|
+
transfer_items: @transfer_items.map(&:to_h)
|
128
|
+
}
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|