Voyz / ibind

IBind is a REST and WebSocket client library for Interactive Brokers Client Portal Web API.
Apache License 2.0
91 stars 11 forks source link

Please add some examples #3

Closed akshayaradhya closed 4 months ago

akshayaradhya commented 4 months ago

Hi,

Really appreciate the efforts in making this library. I have been wrestling with IBKR since quite a while and itโ€™s great to see libraries like this that simplify some things. Could you please add some common examples? Itโ€™s really not that straightforward for someone whoโ€™s not familiar with rest API and web sockets. Here are the examples I would highly appreciate.

Would highly appreciate it if the examples are made available in the repo. The ones that are given already, are not really that straightforward for someone whoโ€™s not familiar with this ecosystem.

Thanks ๐Ÿ™๐Ÿฝ

Voyz commented 4 months ago

Hey @akshayaradhya thank you for the kind words and for trying IBind out.

As for the examples, you write the following:

The ones that are given already, are not really that straightforward for someone whoโ€™s not familiar with this ecosystem.

Hence I assume you've already seen the Examples section?

There indeed you'll find a bunch of the examples you request:

Therefore:

  1. You've listed a few examples that are currently present. What are you missing in the existing examples? You write that they are not that straightforward - I'm sorry to hear that. In fact I tried to keep the examples as straightforward as possible, yet unfortunately several interaction with the API are a bit more complex and currently require a more code to carry out. Could you elaborate here as to what was not straightforward in the existing examples?
  2. As for the option chains - that example is not currently implemented. I appreciate you making the request.
  3. As for scheduling a callback - do you mean just a normal scheduled Python callback or is there a IBKR callback functionality that you refer to here?
Harald-F commented 4 months ago

Hey @akshayaradhya I also recently started to use iBind. Honestly, I have little problems to use it as it is very well documented. What I can suggest that may help you as it helped me:

akshayaradhya commented 4 months ago

@Voyz Sorry for jumping the gun. Yes, you do have some of the examples, I tried them out and many of my requests have now been answered. I still have issues with the following though: โŒ Pulling the options chain, given a ticker โŒ Selecting a certain contract from the given options chain โŒ Scheduling a callback at a given time

For scheduling, I was using this : https://ib-insync.readthedocs.io/api.html#ib_insync.ib.IB.schedule from ib_insync which is a wrapper library around TWS API. I know that it is non 1:1 between CPAPI and TWSAPI, but is there a similar functionality?

Voyz commented 4 months ago

I've just added the new rest_06_options_chain.py example which should hopefully address the first two requests you made. See the official docs for more info on how to do this: https://ibkrcampus.com/ibkr-api-page/cpapi-v1/#oc-step-one

As for the scheduling a callback - unfortunately IBind doesn't have such functionality built in. However, please find the following snippet of code for carrying out such operation yourself easily:

import threading
import time

def run_callback_after_delay(callback, delay):
    """Runs the callback function after a specified delay.

    Args:
        callback (function): The function to be executed after the delay.
        delay (float): The delay time in seconds before executing the callback.
    """
    timer = threading.Timer(delay, callback)
    timer.start()

# Example usage:
def my_callback():
    print("Callback executed!")

run_callback_after_delay(my_callback, 5)  # Executes my_callback after 5 seconds

for i in range(6):
    time.sleep(1)
    print(f'{i+1}s passed...')

Should output:

1s passed...
2s passed...
3s passed...
4s passed...
5s passed...
Callback executed!
6s passed...

Hope these help ๐Ÿ‘

akshayaradhya commented 4 months ago

@Voyz Thank you very much for the example. Highly appreciate it. I improved the example by a bit. The below example finds n contracts with closest strikes to the current price of the underlying expiring on the immediate trading day. Hope it helps :)

Thanks again! Will continue using the library and give you more feedback

"""
REST options chain

In this example we:

* Retrieve an options chain for QQQ

Assumes the Gateway is deployed at 'localhost:5000' and the IBIND_ACCOUNT_ID and IBIND_CACERT environment variables have been set.
"""

import os
from ibind import IbkrClient, ibind_logs_initialize
from pprint import pprint
from datetime import datetime

def find_next_maturity(data_list):
    # Define the format of the date strings
    date_format = "%Y%m%d"

    # Get today's date dynamically
    today = datetime.now()

    # Filter and sort the list of dictionaries by their maturityDate
    future_dates = [item for item in data_list if datetime.strptime(item['maturityDate'], date_format) >= today]

    if not len(future_dates):
        print("No contracts found!")
        return None

    next_item = min(future_dates, key=lambda x: datetime.strptime(x['maturityDate'], date_format))

    return next_item

def find_n_closest_strikes(input_list, value, n):
    # Calculate the absolute difference from the given value for each number in the list
    differences = [(abs(num - value), num) for num in input_list]

    # Sort the list based on the calculated differences
    sorted_by_difference = sorted(differences, key=lambda x: x[0])

    # Extract the top n closest numbers
    closest_strikes = [num for _, num in sorted_by_difference[:n]]

    return sorted(closest_strikes)

ibind_logs_initialize()

cacert = os.getenv('IBIND_CACERT', False)  # insert your cacert path here
client = IbkrClient(cacert=cacert)

print('\n#### search for contract ####')
contracts = client.search_contract_by_symbol('QQQ').data
contract = contracts[0]
pprint(contract)

# find the options section in contract
options = None
for section in contract['sections']:
    if section['secType'] == 'OPT':
        options = section
        break

if options is None:
    raise RuntimeError(f'No options found in contract: {contract}')

expiry = options['months'].split(';')[0]

print('\n#### search for strikes ####')
strikes = client.search_strikes_by_conid(
    conid=contract['conid'],
    sec_type='OPT',
    month=expiry
).data
print(str(strikes).replace("'put'", "\n'put'"))

curr_price = float(client.live_marketdata_snapshot(contract['conid'],['31']).data[0]['31'])

closest_strikes = find_n_closest_strikes(strikes['call'], curr_price, 5)

print('\n#### validate contracts ####')
for strike in closest_strikes:
    for right in ['C','P']:
        info = client.search_secdef_info_by_conid(
            conid=contract['conid'],
            sec_type='OPT',
            month=expiry,
            strike=strike,
            right=right
        ).data
        pprint(find_next_maturity(info))
Voyz commented 4 months ago

Great, happy to help ๐Ÿ˜Š And thanks for sharing your example too ๐Ÿ‘