def setUp(self): self.test_option = Option(ticker='AKS', quantity=1, expiry=date(2018, 8, 10), strike=Decimal('3.5'), option_type=OptionType.CALL, underlying_type=UnderlyingType.EQUITY)
def parse(cls, ticker: str, response: dict): """ Parses a response from tasty session into a dict[str, Option] Args: ticker (str): Ticker symbol of the option chain response (dict): Response from tasty session Returns: dict[str,Option]: dict mapping all option symbols to Option structures """ chain = {} for expiry, strikes in response.items(): for strike, opts in strikes.items(): chain[opts['call']] = Option( ticker=ticker, expiry=datetime.date(expiry), strike=strike, option_type=OptionType.CALL, underlying_type=OptionUnderlyingType. EQUITY, #todo pass underlying ) chain[opts['put']] = Option( ticker=ticker, expiry=datetime.date(expiry), strike=strike, option_type=OptionType.PUT, underlying_type=OptionUnderlyingType. EQUITY, #todo pass underlying ) return chain
def get_option_obj(self): exp_date = datetime.strptime(self.symbol[6:12], '%y%m%d').date() option_type = OptionType(self.symbol[12:13]) strike = Decimal(self.symbol[13:]) / 1000 return Option(ticker=self.underlying_symbol, quantity=self.quantity, expiry=exp_date, strike=strike, option_type=option_type, underlying_type=UnderlyingType.EQUITY)
async def EnterTrade(ticker, price: Decimal, expiry, strike: Decimal, opt_type: OptionType, quantity = 1): sub_values = {"Quote": ["/ES"]} if Settings.EnterWithMarketOrder: details = OrderDetails(type=OrderType.MARKET, price=None, price_effect=OrderPriceEffect.DEBIT) else: details = OrderDetails(type=OrderType.LIMIT, price=price, price_effect=OrderPriceEffect.DEBIT) new_order = Order(details) opt = Option(ticker=ticker, quantity=quantity, expiry=expiry, strike=strike, option_type=opt_type, underlying_type=UnderlyingType.EQUITY) new_order.add_leg(opt) return await tasty_acct.execute_order(new_order, tasty_client, dry_run=False)
def get_equity_leg_from_dict(self, input_dict: dict): exp_date = datetime.strptime(input_dict['symbol'][6:12], '%y%m%d').date() option_type = OptionType(input_dict['symbol'][12:13]) strike = Decimal(input_dict['symbol'][13:]) / 1000 return Option(ticker=self.details.ticker, quantity=input_dict['quantity'], expiry=exp_date, strike=strike, option_type=option_type, underlying_type=UnderlyingType.EQUITY)
async def main_loop(session: TastyAPISession, streamer: DataStreamer): # sub_values = { # "Greeks": [ # ".VIX180718C21", # ".YUM180518C95" # ] # } sub_values = { "Quote": ["/ES"] } accounts = await TradingAccount.get_remote_accounts(session) acct = accounts[0] LOGGER.info('Accounts available: %s', accounts) orders = await Order.get_remote_orders(session, acct) LOGGER.info('Number of active orders: %s', len(orders)) # Execute an order details = OrderDetails( type=OrderType.LIMIT, price=400, price_effect=OrderPriceEffect.CREDIT) new_order = Order(details) opt = Option( ticker='AKS', quantity=1, expiry=date(2018, 10, 19), strike=3.0, option_type=OptionType.CALL, underlying_type=UnderlyingType.EQUITY ) new_order.add_leg(opt) res = await acct.execute_order(new_order, session, dry_run=True) LOGGER.info('Order executed successfully: %s', res) # Get an options chain undl = underlying.Underlying('AKS') chain = await option_chain.get_option_chain(session, undl) LOGGER.info('Chain strikes: %s', chain.get_all_strikes()) await streamer.add_data_sub(sub_values) async for item in streamer.listen(): LOGGER.info('Received item: %s' % item.data)
class TestOptionModel(unittest.TestCase): def setUp(self): self.test_option = Option( ticker='AKS', quantity=1, expiry=date(2018, 8, 10), strike=3.5, option_type=OptionType.CALL, underlying_type=OptionUnderlyingType.EQUITY ) def test_occ2010_integer_strike(self): self.test_option.strike = 3 expected_result = 'AKS 180810C00003000' res = self.test_option.get_occ2010_symbol() self.assertEqual(expected_result, res) def test_occ2010_fraction_strike(self): self.test_option.strike = 3.45 expected_result = 'AKS 180810C00003450' res = self.test_option.get_occ2010_symbol() self.assertEqual(expected_result, res) self.test_option.strike = 3.5 expected_result = 'AKS 180810C00003500' res = self.test_option.get_occ2010_symbol() self.assertEqual(expected_result, res) def test_occ2010_ticker_padding(self): self.test_option.ticker = 'BOB123' expected_result = 'BOB123180810C00003500' res = self.test_option.get_occ2010_symbol() self.assertEqual(expected_result, res) self.test_option.ticker = 'BOB' expected_result = 'BOB 180810C00003500' res = self.test_option.get_occ2010_symbol() self.assertEqual(expected_result, res) def test_occ2010_ticker_trimming(self): self.test_option.ticker = 'BOB123456' expected_result = 'BOB123180810C00003500' res = self.test_option.get_occ2010_symbol() self.assertEqual(expected_result, res)
async def get_option_chain(session, underlying: Underlying, expiration: date = None) -> List[Option]: LOGGER.debug('Getting options chain for ticker: %s', underlying.ticker) data = await _get_tasty_option_chain_data(session, underlying) res = [] for exp in data['expirations']: exp_date = datetime.strptime(exp['expiration-date'], '%Y-%m-%d').date() if expiration and expiration != exp_date: continue for strike in exp['strikes']: strike_val = float(strike['strike-price']) for option_types in OptionType: new_option = Option( ticker=underlying.ticker, expiry=exp_date, strike=strike_val, option_type=option_types, underlying_type=UnderlyingType.EQUITY ) res.append(new_option) return OptionChain(res)
class TestOptionModel(unittest.TestCase): def setUp(self): self.test_option = Option(ticker='AKS', quantity=1, expiry=date(2018, 8, 10), strike=Decimal('3.5'), option_type=OptionType.CALL, underlying_type=UnderlyingType.EQUITY) def test_occ2010_integer_strike(self): self.test_option.strike = 3 expected_result = 'AKS 180810C00003000' res = self.test_option.get_occ2010_symbol() self.assertEqual(expected_result, res) def test_occ2010_fraction_strike(self): self.test_option.strike = 3.45 expected_result = 'AKS 180810C00003450' res = self.test_option.get_occ2010_symbol() self.assertEqual(expected_result, res) self.test_option.strike = 3.5 expected_result = 'AKS 180810C00003500' res = self.test_option.get_occ2010_symbol() self.assertEqual(expected_result, res) def test_occ2010_ticker_padding(self): self.test_option.ticker = 'BOB123' expected_result = 'BOB123180810C00003500' res = self.test_option.get_occ2010_symbol() self.assertEqual(expected_result, res) self.test_option.ticker = 'BOB' expected_result = 'BOB 180810C00003500' res = self.test_option.get_occ2010_symbol() self.assertEqual(expected_result, res) def test_occ2010_ticker_trimming(self): self.test_option.ticker = 'BOB123456' expected_result = 'BOB123180810C00003500' res = self.test_option.get_occ2010_symbol() self.assertEqual(expected_result, res) def test_get_dxfeed_symbol(self): expected_result = '.AKS180810C3.5' result = self.test_option.get_dxfeed_symbol() self.assertEqual(result, expected_result) def test_no_option_chains_on_option(self): with self.assertRaises(Exception): self.test_option.get_option_chain() def test_get_underlying_type_string(self): res = self.test_option._get_underlying_type_string( UnderlyingType.EQUITY) self.assertEqual(res, 'Equity Option') def test_to_tasty_json(self): res = self.test_option.to_tasty_json() expected_result = { 'instrument-type': 'Equity Option', 'symbol': 'AKS 180810C00003500', 'quantity': 1 } self.assertDictEqual(res, expected_result)
async def call(underlying: str, quantity: int, strike: Optional[int] = None, all_expirations: Optional[bool] = False, delta: Optional[int] = None): if strike is not None and delta is not None: raise TastyworksCLIError( 'Must specify either delta or strike, but not both.') elif not strike and not delta: raise TastyworksCLIError( 'Please specify either delta or strike for the option.') elif abs(delta) > 100: raise TastyworksCLIError( 'Delta value is too high, -100 <= delta <= 100') sesh = await RenewableTastyAPISession.create() undl = Underlying(underlying) expiration = await choose_expiration(sesh, undl, all_expirations) streamer = await DataStreamer.create(sesh) if not strike: chain = await get_option_chain(sesh, undl, expiration) dxfeeds = [ option.symbol_dxf for option in chain.options if option.option_type == OptionType.CALL ] greeks = await streamer.stream('Greeks', dxfeeds) lowest = abs(greeks[0]['delta'] * 100.0 - delta) index = 0 for i in range(1, len(greeks)): diff = abs(greeks[i]['delta'] * 100.0 - delta) if diff < lowest: index = i lowest = diff for option in chain.options: if option.symbol_dxf == greeks[index]['eventSymbol']: strike = option.strike break option = Option(ticker=underlying, quantity=abs(quantity), expiry=expiration, strike=strike, option_type=OptionType.CALL, underlying_type=UnderlyingType.EQUITY) quote = await streamer.stream('Quote', [option.symbol_dxf]) bid = quote[0]['bidPrice'] ask = quote[0]['askPrice'] mid = (bid + ask) / 2 await streamer.close() console = Console() table = Table(show_header=True, header_style='bold', title_style='bold', title=f'Quote for {underlying} {strike}C {expiration}') table.add_column('Bid', style='green', width=8, justify='center') table.add_column('Mid', width=8, justify='center') table.add_column('Ask', style='red', width=8, justify='center') table.add_row(f'{bid:.2f}', f'{mid:.2f}', f'{ask:.2f}') console.print(table) price = input( 'Please enter a limit price for the entire order (default mid): ') if not price: price = round(mid * abs(quantity), 2) price = Decimal(price) details = OrderDetails(type=OrderType.LIMIT, price=price, price_effect=OrderPriceEffect.CREDIT if quantity < 0 else OrderPriceEffect.DEBIT) order = Order(details) order.add_leg(option) acct = await get_account(sesh) details = await acct.get_balance(sesh) nl = Decimal(details['net-liquidating-value']) data = await acct.execute_order(order, sesh, dry_run=True) bp = Decimal(data['buying-power-effect']['change-in-buying-power']) percent = bp / nl * Decimal(100) # bp_effect = data['buying-power-effect']['change-in-buying-power-effect'] fees = Decimal(data['fee-calculation']['total-fees']) table = Table(show_header=True, header_style='bold', title_style='bold', title='Order Review') table.add_column('Quantity', width=8, justify='center') table.add_column('Symbol', width=8, justify='center') table.add_column('Strike', width=8, justify='center') table.add_column('Type', width=8, justify='center') table.add_column('Expiration', width=10, justify='center') table.add_column('Price', width=8, justify='center') table.add_column('BP', width=8, justify='center') table.add_column('% of NL', width=8, justify='center') table.add_column('Fees', width=8, justify='center') table.add_row(f'{quantity}', underlying, f'{strike:.2f}', 'CALL', f'{expiration}', f'${price:.2f}', f'${bp:.2f}', f'{percent:.2f}%', f'${fees}') console.print(table) if data['warnings']: console.print('[bold orange]Warnings:[/bold orange]') for warning in data['warnings']: console.print(f'[i gray]{warning}[/i gray]') if get_confirmation('Send order? Y/n '): await acct.execute_order(order, sesh, dry_run=False)