Skip to content

Commit

Permalink
Merge pull request #64 from alexgolec/options-symbol-documentatio
Browse files Browse the repository at this point in the history
Update options symbol documentation
  • Loading branch information
alexgolec authored May 14, 2024
2 parents 3c9c711 + 73cb5f8 commit 8e5b01d
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 23 deletions.
7 changes: 6 additions & 1 deletion docs/order-templates.rst
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ Note orders placed using these templates may be rejected, depending on the
user's options trading authorization.



.. _options_symbols:

++++++++++++++++++++++++
Building Options Symbols
++++++++++++++++++++++++
Expand All @@ -135,7 +138,9 @@ and does not validate whether the symbol actually represents a traded option:
'TSLA', datetime.date(year=2020, month=11, day=20), 'P', '1360').build()
.. autoclass:: schwab.orders.options.OptionSymbol
:special-members:
:special-members:

.. automethod:: schwab.orders.options.OptionSymbol.build


++++++++++++++
Expand Down
10 changes: 10 additions & 0 deletions docs/tda-transition.rst
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@ Again, **this is not a choice by the library authors.** Please do not go to our
Discord server asking to recover your data or add this functionality.


+++++++++++++++++++++++++++++++++++++++++
Options symbols are formatted differently
+++++++++++++++++++++++++++++++++++++++++

Options symbols on Schwab use a different format than they did on TDAmeritrade.
Code that manipulates them may need to be updated. ``schwab-py`` provides a
:ref:`helper class<options_symbols>` to make parsing and generating options
symbols easier.


++++++++++++++++++++++++++++++++++++++++++++++
``schwab-py`` only supports python 3.10 and up
++++++++++++++++++++++++++++++++++++++++++++++
Expand Down
45 changes: 23 additions & 22 deletions schwab/orders/options.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,16 @@ def _parse_expiration_date(expiration_date):


class OptionSymbol:
'''Construct an option symbol from its constituent parts. Options symbols
have the following format: ``[Underlying left justified with spaces to 6 positions]
[Two digit year][Two digit month][Two digit day]['P' or 'C'][Strike price]``
'''Construct an option symbol from its constituent parts.
The format of the strike price is modified based on its amount:
* If less than 1000, Strike Price is multiple by 1000 and pre-pended with
two zeroes
* If greater than 1000, it's prepended with one zero.
Examples include:
* ``QQQ 240420P00500000``: QQQ Apr 20, 2024 500 Put (note the two zeroes
in front because strike is less than 1000)
* ``SPXW 240420C05040000``: SPX Weekly Apr 20, 2024 5040 Call (note the
one zero in front because strike is greater than 1000)
:param underlying_symbol: Symbol of the underlying. Not validated.
:param expiration_date: Expiration date. Accepts ``datetime.date``,
``datetime.datetime``, or strings with the
format ``[Two digit year][Two digit month][Two
digit day]``.
:param contract_type: ``P`` or ``PUT`` for put and ``C`` or ``CALL`` for
call.
:param strike_price_as_string: Strike price represented as a decimal string.
Note while each of the individual parts is validated by itself, the
option symbol itself may not represent a traded option:
Expand All @@ -44,15 +40,20 @@ class OptionSymbol:
option symbols for an underlying, as well as extensive data in pricing,
bid/ask spread, volume, etc.
:param underlying_symbol: Symbol of the underlying. Not validated.
:param expiration_date: Expiration date. Accepts ``datetime.date``,
``datetime.datetime``, or strings with the
format ``[Two digit year][Two digit month][Two
digit day]``.
:param contract_type: ``P` or `PUT`` for put and ``C` or `CALL`` for call.
:param strike_price_as_string: Strike price, represented by a string as
you would see at the end of a real option
symbol.
For those interested in the details, options symbols have the following
format: ``[Underlying left justified with spaces to 6 positions] [Two digit
year][Two digit month][Two digit day]['P' or 'C'][Strike price]``
The format of the strike price is modified based on its amount:
* If less than 1000, Strike Price is multiple by 1000 and pre-pended with
two zeroes
* If greater than 1000, it's prepended with one zero.
Examples include:
* ``QQQ 240420P00500000``: QQQ Apr 20, 2024 500 Put (note the two zeroes
in front because strike is less than 1000)
* ``SPXW 240420C05040000``: SPX Weekly Apr 20, 2024 5040 Call (note the
one zero in front because strike is greater than 1000)
'''

Expand Down
27 changes: 27 additions & 0 deletions tests/orders/options_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,33 @@ def test_strike_over_1000(self):

self.assertEqual('BKNG 240510C02400000', op.build())

def test_strike_ends_in_decimal_point(self):
op = OptionSymbol('AAPL', datetime.date(2024, 5, 10), 'C', '100.')
self.assertEqual('AAPL 240510C00100000', op.build())

def test_strike_ends_in_trailing_zeroes(self):
op = OptionSymbol('AAPL', datetime.date(2024, 5, 10), 'C',
'100.00000000')
self.assertEqual('AAPL 240510C00100000', op.build())

def test_CALL_as_delimiter(self):
op = OptionSymbol('AAPL', datetime.date(2024, 5, 10), 'CALL', '100.10')
self.assertEqual('AAPL 240510C00100100', op.build())

def test_PUT_as_delimiter(self):
op = OptionSymbol('AAPL', datetime.date(2024, 5, 10), 'CALL', '100.10')
self.assertEqual('AAPL 240510C00100100', op.build())

def test_invalid_strike(self):
with self.assertRaisesRegex(
ValueError, '.*option must have contract type.*'):
op = OptionSymbol.parse_symbol('BKNG 240510Q02400000')


def test_date_as_string(self):
op = OptionSymbol('AAPL', '261218', 'P', '350')
self.assertEqual('AAPL 261218P00350000', op.build())


def test_strike_as_float(self):
with self.assertRaisesRegex(
Expand Down

0 comments on commit 8e5b01d

Please sign in to comment.