Class: SecID::OCC

Inherits:
Base
  • Object
show all
Defined in:
lib/sec_id/occ.rb

Overview

Note:

OCC identifiers have no check digit and validation includes both format and date parseability checks.

OCC Option Symbol - standardized option symbol format used by Option Clearing Corporation. Format: 6-char underlying (padded) + 6-char date (YYMMDD) + type (C/P) + 8-digit strike (in mills).

Examples:

Validate an OCC symbol

SecID::OCC.valid?('AAPL  210917C00150000')  #=> true

Build an OCC symbol from components

occ = SecID::OCC.build(underlying: 'AAPL', date: '2021-09-17', type: 'C', strike: 150.0)
occ.to_s  #=> 'AAPL  210917C00150000'

See Also:

Constant Summary collapse

FULL_NAME =

Human-readable name of the standard.

'OCC Option Symbol'
ID_LENGTH =

Valid length(s) of a normalized identifier.

(16..21)
EXAMPLE =

A representative valid identifier.

'AAPL  210917C00150000'
VALID_CHARS_REGEX =

Pattern matching the identifier's permitted character set.

/\A[A-Z0-9 ]+\z/
SEPARATORS =

Separators stripped during normalization; spaces are structural here, so only hyphens.

/-/
ID_REGEX =

Regular expression for parsing OCC symbol components.

/\A
  (?<initial>
    (?=.{1,6})(?<underlying>\d?[A-Z]{1,5}\d?)(?<padding>[ ]*))
  (?<date>\d{6})
  (?<type>[CP])
  (?<strike_mills>\d{8})
\z/x

Constants included from Generatable

Generatable::ALPHA, Generatable::ALPHANUMERIC, Generatable::DIGITS

Constants included from Validatable

Validatable::ERROR_MAP

Instance Attribute Summary collapse

Attributes inherited from Base

#full_id, #identifier

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Base

#==, #as_json, example, full_name, has_check_digit?, #hash, id_length, length_specificity, length_values, short_name, #to_h

Methods included from Validatable

#errors, #validate, #validate!

Methods included from Normalizable

#normalize!, #to_str

Constructor Details

#initialize(symbol) ⇒ OCC

Returns a new instance of OCC.

Parameters:

  • symbol (String)

    the OCC symbol string to parse



118
119
120
121
122
123
124
125
# File 'lib/sec_id/occ.rb', line 118

def initialize(symbol)
  symbol_parts = parse(symbol)
  @identifier = symbol_parts[:initial]
  @underlying = symbol_parts[:underlying]
  @date_str = symbol_parts[:date]
  @type = symbol_parts[:type]
  @strike_mills = symbol_parts[:strike_mills]
end

Instance Attribute Details

#date_strString? (readonly)

Returns the expiration date string in YYMMDD format.

Returns:

  • (String, nil)

    the expiration date string in YYMMDD format



46
47
48
# File 'lib/sec_id/occ.rb', line 46

def date_str
  @date_str
end

#strike_millsString? (readonly)

Returns the strike price in mills (thousandths of a dollar, represented as an 8-digit string).

Returns:

  • (String, nil)

    the strike price in mills (thousandths of a dollar, represented as an 8-digit string)



52
53
54
# File 'lib/sec_id/occ.rb', line 52

def strike_mills
  @strike_mills
end

#typeString? (readonly)

Returns the option type ('C' for call, 'P' for put).

Returns:

  • (String, nil)

    the option type ('C' for call, 'P' for put)



49
50
51
# File 'lib/sec_id/occ.rb', line 49

def type
  @type
end

#underlyingString? (readonly)

Returns the underlying security symbol (1-6 chars).

Returns:

  • (String, nil)

    the underlying security symbol (1-6 chars)



43
44
45
# File 'lib/sec_id/occ.rb', line 43

def underlying
  @underlying
end

Class Method Details

.build(underlying:, date:, type:, strike:) ⇒ OCC

Builds an OCC symbol from components.

Parameters:

  • underlying (String)

    the underlying symbol (1-6 chars)

  • date (String, Date)

    the expiration date

  • type (String)

    'C' for call or 'P' for put

  • strike (Numeric, String)

    the strike price in dollars or 8-char mills string

Returns:

  • (OCC)

    a new OCC instance

Raises:

  • (ArgumentError)

    if strike format is invalid



79
80
81
82
83
84
# File 'lib/sec_id/occ.rb', line 79

def build(underlying:, date:, type:, strike:)
  date_obj = date.is_a?(Date) ? date : Date.parse(date)
  strike_mills = normalize_strike_mills(strike)

  new(compose_symbol(underlying, date_obj.strftime('%y%m%d'), type, strike_mills))
end

.compose_symbol(underlying, date_str, type, strike_mills) ⇒ String

Composes an OCC symbol string from its components.

Parameters:

  • underlying (String)

    the underlying symbol

  • date_str (String)

    the date in YYMMDD format

  • type (String)

    'C' or 'P'

  • strike_mills (String, Integer)

    the strike in mills

Returns:

  • (String)

    the composed OCC symbol



93
94
95
96
97
98
# File 'lib/sec_id/occ.rb', line 93

def compose_symbol(underlying, date_str, type, strike_mills)
  padded_underlying = underlying.to_s.ljust(6, "\s")
  padded_strike = format('%08d', strike_mills.to_i)

  "#{padded_underlying}#{date_str}#{type}#{padded_strike}"
end

.generate(random: Random.new) ⇒ OCC

Note:

Generated symbols are valid in format only — they are not real, listed options.

Generates a random OCC option symbol.

Parameters:

  • random (Random) (defaults to: Random.new)

    source of randomness

Returns:

  • (OCC)

    a generated, valid OCC instance



60
61
62
63
64
65
66
67
68
# File 'lib/sec_id/occ.rb', line 60

def self.generate(random: Random.new)
  build(
    underlying: random_string(ALPHA, random.rand(1..5), random: random),
    # Year 2000-2068 so the 2-digit-year symbol round-trips: strptime maps %y 69-99 to 19xx.
    date: Date.new(2000 + random.rand(0..68), random.rand(1..12), random.rand(1..28)),
    type: %w[C P].sample(random: random),
    strike: random_string(DIGITS, 8, random: random)
  )
end

Instance Method Details

#dateDate? Also known as: date_obj

Returns the parsed date or nil if invalid.

Returns:

  • (Date, nil)

    the parsed date or nil if invalid



140
141
142
143
144
145
146
147
# File 'lib/sec_id/occ.rb', line 140

def date
  return @date if defined?(@date)
  return unless date_str

  @date = Date.strptime(date_str, '%y%m%d')
rescue ArgumentError
  @date = nil
end

#normalizedString

Returns the normalized OCC symbol.

Returns:

  • (String)

    the normalized OCC symbol

Raises:



129
130
131
132
# File 'lib/sec_id/occ.rb', line 129

def normalized
  validate!
  self.class.compose_symbol(underlying, date_str, type, strike_mills)
end

#strikeFloat?

Returns strike price in dollars.

Returns:

  • (Float, nil)

    strike price in dollars



151
152
153
154
155
# File 'lib/sec_id/occ.rb', line 151

def strike
  return @strike if defined?(@strike)

  @strike = strike_mills&.then { |m| m.to_i / 1000.0 }
end

#to_pretty_sString?

Returns:

  • (String, nil)


163
164
165
166
167
# File 'lib/sec_id/occ.rb', line 163

def to_pretty_s
  return nil unless valid?

  "#{underlying} #{date_str} #{type} #{strike_mills}"
end

#to_sString

Returns:

  • (String)


158
159
160
# File 'lib/sec_id/occ.rb', line 158

def to_s
  full_id
end

#valid?Boolean

Returns:

  • (Boolean)


135
136
137
# File 'lib/sec_id/occ.rb', line 135

def valid?
  valid_format? && !date.nil? # date must be parseable
end