Module: SchwabRb::OptionSample::Downloader
- Defined in:
- lib/schwab_rb/option_sample/downloader.rb
Overview
Public file-oriented downloader for one-expiration option chain samples.
Constant Summary collapse
- SUPPORTED_FORMATS =
%w[csv json].freeze
- CSV_HEADERS =
%w[ contract_type symbol description strike expiration_date mark bid bid_size ask ask_size last last_size open_interest total_volume delta gamma theta vega rho volatility theoretical_volatility theoretical_option_value intrinsic_value extrinsic_value underlying_price ].freeze
Class Method Summary collapse
- .blank?(value) ⇒ Boolean
-
.csv_row(response, option, _sample_timestamp) ⇒ Object
rubocop:disable Metrics/AbcSize.
-
.fetch(client:, symbol:, expiration_date:, root: nil) ⇒ Object
rubocop:enable Metrics/ParameterLists.
- .filter_date_map_by_root(date_map, option_root) ⇒ Object
- .filter_response_by_root(response, option_root) ⇒ Object
- .normalize_option_date(value) ⇒ Object
- .option_root(response, fallback_symbol) ⇒ Object
-
.output_path(directory:, symbol:, expiration_date:, format:, timestamp:, root: nil, response: nil) ⇒ Object
rubocop:disable Metrics/ParameterLists.
-
.resolve(client:, symbol:, expiration_date:, directory:, format:, timestamp:, root: nil) ⇒ Object
rubocop:disable Metrics/ParameterLists.
-
.rows(response) ⇒ Object
rubocop:enable Metrics/AbcSize.
- .rows_from_date_map(date_map) ⇒ Object
-
.serialize(response:, format:, timestamp:) ⇒ Object
rubocop:enable Metrics/ParameterLists.
- .serialize_csv(response:, timestamp:) ⇒ Object
Class Method Details
.blank?(value) ⇒ Boolean
205 206 207 |
# File 'lib/schwab_rb/option_sample/downloader.rb', line 205 def blank?(value) value.nil? || value.to_s.strip.empty? end |
.csv_row(response, option, _sample_timestamp) ⇒ Object
rubocop:disable Metrics/AbcSize
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/schwab_rb/option_sample/downloader.rb', line 143 def csv_row(response, option, ) [ option[:putCall], option[:symbol], option[:description], option[:strikePrice], normalize_option_date(option[:expirationDate]), option[:mark], option[:bid], option[:bidSize], option[:ask], option[:askSize], option[:last], option[:lastSize], option[:openInterest], option[:totalVolume], option[:delta], option[:gamma], option[:theta], option[:vega], option[:rho], option[:volatility], option[:theoreticalVolatility], option[:theoreticalOptionValue], option[:intrinsicValue], option[:extrinsicValue], response[:underlyingPrice] ] end |
.fetch(client:, symbol:, expiration_date:, root: nil) ⇒ Object
rubocop:enable Metrics/ParameterLists
68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/schwab_rb/option_sample/downloader.rb', line 68 def fetch(client:, symbol:, expiration_date:, root: nil) response = client.get_option_chain( SchwabRb::PriceHistory::Downloader.api_symbol(symbol), contract_type: SchwabRb::Option::ContractTypes::ALL, strike_range: SchwabRb::Option::StrikeRanges::ALL, from_date: expiration_date, to_date: expiration_date, return_data_objects: false ) filter_response_by_root(response, root) end |
.filter_date_map_by_root(date_map, option_root) ⇒ Object
92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/schwab_rb/option_sample/downloader.rb', line 92 def filter_date_map_by_root(date_map, option_root) return {} unless date_map date_map.each_with_object({}) do |(expiration_key, strikes), filtered_dates| filtered_strikes = strikes.each_with_object({}) do |(strike, contracts), filtered_by_strike| matching_contracts = contracts.select { |contract| contract[:optionRoot].to_s.upcase == option_root } filtered_by_strike[strike] = matching_contracts if matching_contracts.any? end filtered_dates[expiration_key] = filtered_strikes if filtered_strikes.any? end end |
.filter_response_by_root(response, option_root) ⇒ Object
81 82 83 84 85 86 87 88 89 90 |
# File 'lib/schwab_rb/option_sample/downloader.rb', line 81 def filter_response_by_root(response, option_root) return response if blank?(option_root) normalized_root = option_root.to_s.strip.upcase response.merge( callExpDateMap: filter_date_map_by_root(response[:callExpDateMap], normalized_root), putExpDateMap: filter_date_map_by_root(response[:putExpDateMap], normalized_root) ) end |
.normalize_option_date(value) ⇒ Object
199 200 201 202 203 |
# File 'lib/schwab_rb/option_sample/downloader.rb', line 199 def normalize_option_date(value) return if value.nil? Date.parse(value.to_s).iso8601 end |
.option_root(response, fallback_symbol) ⇒ Object
194 195 196 197 |
# File 'lib/schwab_rb/option_sample/downloader.rb', line 194 def option_root(response, fallback_symbol) first_option = rows(response).find { |option| !blank?(option[:optionRoot]) } first_option ? first_option[:optionRoot] : fallback_symbol end |
.output_path(directory:, symbol:, expiration_date:, format:, timestamp:, root: nil, response: nil) ⇒ Object
rubocop:disable Metrics/ParameterLists
106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/schwab_rb/option_sample/downloader.rb', line 106 def output_path(directory:, symbol:, expiration_date:, format:, timestamp:, root: nil, response: nil) selected_root = root || option_root(response, symbol) File.join( directory, [ SchwabRb::PriceHistory::Downloader.sanitize_symbol(selected_root), "exp#{expiration_date.iso8601}", .strftime("%Y-%m-%d_%H-%M-%S") ].join("_") + ".#{format}" ) end |
.resolve(client:, symbol:, expiration_date:, directory:, format:, timestamp:, root: nil) ⇒ Object
rubocop:disable Metrics/ParameterLists
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/schwab_rb/option_sample/downloader.rb', line 44 def resolve(client:, symbol:, expiration_date:, directory:, format:, timestamp:, root: nil) response = fetch( client: client, symbol: symbol, expiration_date: expiration_date, root: root ) FileUtils.mkdir_p(directory) path = output_path( directory: directory, symbol: symbol, expiration_date: expiration_date, format: format, timestamp: , root: root, response: response ) File.write(path, serialize(response: response, format: format, timestamp: )) [response, path] end |
.rows(response) ⇒ Object
rubocop:enable Metrics/AbcSize
174 175 176 177 178 179 180 181 182 183 184 185 186 |
# File 'lib/schwab_rb/option_sample/downloader.rb', line 174 def rows(response) extracted_rows = [response[:callExpDateMap], response[:putExpDateMap]].compact.flat_map do |date_map| rows_from_date_map(date_map) end extracted_rows.sort_by do |option| [ normalize_option_date(option[:expirationDate]).to_s, option[:putCall].to_s, option[:strikePrice].to_f ] end end |
.rows_from_date_map(date_map) ⇒ Object
188 189 190 191 192 |
# File 'lib/schwab_rb/option_sample/downloader.rb', line 188 def rows_from_date_map(date_map) date_map.values.flat_map do |strikes| strikes.values.flatten.map { |option| option.transform_keys(&:to_sym) } end end |
.serialize(response:, format:, timestamp:) ⇒ Object
rubocop:enable Metrics/ParameterLists
120 121 122 123 124 125 126 127 128 129 |
# File 'lib/schwab_rb/option_sample/downloader.rb', line 120 def serialize(response:, format:, timestamp:) case format when "json" JSON.pretty_generate(response) when "csv" serialize_csv(response: response, timestamp: ) else raise ArgumentError, "Unsupported format `#{format}`." end end |
.serialize_csv(response:, timestamp:) ⇒ Object
131 132 133 134 135 136 137 138 139 140 |
# File 'lib/schwab_rb/option_sample/downloader.rb', line 131 def serialize_csv(response:, timestamp:) = .utc.iso8601 CSV.generate do |csv| csv << CSV_HEADERS rows(response).each do |option| csv << csv_row(response, option, ) end end end |