Kotak-Neo / kotak-neo-api

113 stars 105 forks source link

[FEAT] Reuse the session after client initialization #66

Open darshil-lakhani opened 1 year ago

darshil-lakhani commented 1 year ago

Current Behavior:

Currently when we initialize the client using the below mentioned code

from neo_api_client import NeoAPI
client = NeoAPI(consumer_key="", consumer_secret="", 
                environment='uat', on_message=on_message, on_error=on_error, on_close=None, on_open=None)
client.login(mobilenumber="+919999999999", password="XXXX")
client.session_2fa(OTP="")

We are unable to reuse the session token for further initialization.

Expected Behavior:

We Should be able to initiate the client using something like

reuse_session = {}
client = NeoAPI(access_token="",environment="prod",reuse_session=reuse_session)
#or
client = NeoAPI(consumer_key="", consumer_secret="",reuse_session=reuse_session
                environment='prod')

(You can use on_message, on_error , on_close and on_open in both the ways ) By doing so we should be able to able to initialize the client without using username, password, OTP or MPIN

But currently we are not able to do that, it gives us this error when we try to access any method of client object

{'Error Message': 'Complete the 2fa process before accessing this application'}
Hari3115 commented 1 year ago

client.session_2fa(OTP="") write this code in a separate cell, so that once the otp is generated you can put in the code and run it separately

darshil-lakhani commented 1 year ago

client.session_2fa(OTP="") write this code in a separate cell, so that once the otp is generated you can put in the code and run it separately

I have created a PR with the solution for this issue which I have raised. what you said was not relevant to this issue i guess. This issue is about reusing the client session once OTP is entered and then again if you want to initiate that client with same session ( lets say you restart your application, in that case you can reuse the session to initiate the client without generating the OTP again ). I hope its clear now.

govindsah1234 commented 1 year ago

from neo_api_client import NeoAPI

Initialize the NeoAPI client

client = NeoAPI(

consumer_key="",

consumer_secret="",
environment="prod"

)

Your mobile number and password

mobilenumber = "" password = ""

try:

Run login to obtain OTP (Do not complete 2FA)

login_response = client.login(mobilenumber=mobilenumber, password=password)

# Check if the login response indicates success or contains an error
if login_response and login_response.get("data"):
    print("Login successful")
elif login_response and login_response.get("error"):
    print("Login failed with the following error:")
    print(login_response["error"]["message"])
else:
    print("Unexpected response from the server")

# Wait for OTP to arrive and store it in a variable or file
received_otp = input("Enter the OTP you received: ")  # You can modify this part to read from a file

# Run the 2FA code separately with the stored OTP
response = client.session_2fa(OTP=received_otp)

# Check if the response indicates success or contains an error
if response and response.get("data"):
    print("2FA completed successfully")
elif response and response.get("error"):
    print("2FA failed with the following error:")
    print(response["error"]["message"])
else:
    print("Unexpected response from the server")

# Save the response to a text file
with open("response.txt", "w") as file:
    file.write(str(response))

except Exception as e: print("Exception when calling SessionApi->session_2fa: %s\n" % e)

youngking1686 commented 1 year ago

There are 2 ways you can do it without having to repeatedly dealing with OTP. 1) provide your MPIN instead of your OTP 2) Pickle the client object into to a file and read the file to retrieve your session object whenever required without having to login again.

geek-coder commented 1 year ago

from neo_api_client import NeoAPI

Initialize the NeoAPI client

client = NeoAPI(

consumer_key="",

consumer_secret="",
environment="prod"

)

Your mobile number and password

mobilenumber = "" password = ""

try: # Run login to obtain OTP (Do not complete 2FA) login_response = client.login(mobilenumber=mobilenumber, password=password)

# Check if the login response indicates success or contains an error
if login_response and login_response.get("data"):
    print("Login successful")
elif login_response and login_response.get("error"):
    print("Login failed with the following error:")
    print(login_response["error"]["message"])
else:
    print("Unexpected response from the server")

# Wait for OTP to arrive and store it in a variable or file
received_otp = input("Enter the OTP you received: ")  # You can modify this part to read from a file

# Run the 2FA code separately with the stored OTP
response = client.session_2fa(OTP=received_otp)

# Check if the response indicates success or contains an error
if response and response.get("data"):
    print("2FA completed successfully")
elif response and response.get("error"):
    print("2FA failed with the following error:")
    print(response["error"]["message"])
else:
    print("Unexpected response from the server")

# Save the response to a text file
with open("response.txt", "w") as file:
    file.write(str(response))

except Exception as e: print("Exception when calling SessionApi->session_2fa: %s\n" % e)

There are 2 ways you can do it without having to repeatedly dealing with OTP.

  1. provide your MPIN instead of your OTP
  2. Pickle the client object into to a file and read the file to retrieve your session object whenever required without having to login again.

both ways don't work for placing orders. For just live streaming, pickling works atleast. And I think live streaming works without any of two ways mentioned also. They have two kind of tokens view_token, edit_token . view_token works, edit does not.

crypt0inf0 commented 9 months ago

It returns this error {'code': '900901', 'message': 'Invalid Credentials', 'description': 'Invalid JWT token. Make sure you have provided the correct security credentials'}

with open("creds.json","r") as file:
    reuse_session = json.load(file)

client = NeoAPI(consumer_key=consumer_key,
            consumer_secret=consumer_secret,
            environment=environment, reuse_session=reuse_session)
darshil-lakhani commented 9 months ago

It returns this error {'code': '900901', 'message': 'Invalid Credentials', 'description': 'Invalid JWT token. Make sure you have provided the correct security credentials'}

with open("creds.json","r") as file:
    reuse_session = json.load(file)

client = NeoAPI(consumer_key=consumer_key,
            consumer_secret=consumer_secret,
            environment=environment, reuse_session=reuse_session)

That means that your access token is expired, so then you need to re-login and get a new access token. FYI you can change your expiry time of access token at your tradeapi portal .

crypt0inf0 commented 9 months ago

@darshil-lakhani Ok, Thanks.

Aadarsh131 commented 3 months ago

I tried to solve the original problem simply by storing the authenticated object into a new file and then fetching it whenever required, here is the code-

import pickle #helps to copy objects in a file

try:
  with open('authenticated_client.pickle','rb') as file:
    client = pickle.load(file)

except:
  client = NeoAPI(consumer_key="xxxx", consumer_secret="xxxx", environment='prod',
                  access_token=None, neo_fin_key=None)
  client.login(mobilenumber="xxxx", password="xxxx")
  client.session_2fa(OTP=xxxx)

  with open('authenticated_client.pickle','wb') as file:
    pickle.dump(client,file)
    print('New login')

# NOW USE THE `client` object as usual
shitizbansal247 commented 2 months ago

I tried to solve the original problem simply by storing the authenticated object into a new file and then fetching it whenever required, here is the code-

import pickle #helps to copy objects in a file

try:
  with open('authenticated_client.pickle','rb') as file:
    client = pickle.load(file)

except:
  client = NeoAPI(consumer_key="xxxx", consumer_secret="xxxx", environment='prod',
                  access_token=None, neo_fin_key=None)
  client.login(mobilenumber="xxxx", password="xxxx")
  client.session_2fa(OTP=xxxx)

  with open('authenticated_client.pickle','wb') as file:
    pickle.dump(client,file)
    print('New login')

# NOW USE THE `client` object as usual

thanks aadarsh131. this bit of code was really helpful.

tradeautumn commented 1 week ago

Current Behavior:

Currently when we initialize the client using the below mentioned code

from neo_api_client import NeoAPI
client = NeoAPI(consumer_key="", consumer_secret="", 
                environment='uat', on_message=on_message, on_error=on_error, on_close=None, on_open=None)
client.login(mobilenumber="+919999999999", password="XXXX")
client.session_2fa(OTP="")

We are unable to reuse the session token for further initialization.

Expected Behavior:

We Should be able to initiate the client using something like

reuse_session = {}
client = NeoAPI(access_token="",environment="prod",reuse_session=reuse_session)
#or
client = NeoAPI(consumer_key="", consumer_secret="",reuse_session=reuse_session
                environment='prod')

(You can use on_message, on_error , on_close and on_open in both the ways ) By doing so we should be able to able to initialize the client without using username, password, OTP or MPIN

But currently we are not able to do that, it gives us this error when we try to access any method of client object

{'Error Message': 'Complete the 2fa process before accessing this application'}

Just use the following code before API function call client.configuration.serverId = session_data.loc[0].server_id client.configuration.edit_token = session_data.loc[0].session_token client.configuration.edit_sid = session_data.loc[0].session_id client.trade_report()

The session_data is saved from previous session_2fa call: session_df = pd.DataFrame(client.session_2fa(OTP=motp))

    new_data = pd.DataFrame({
        'session_token' : [session_df.data.token],
        'session_id'    : [session_df.data.sid],
        'server_id'     : [session_df.data.hsServerId]
    })
workdesk96 commented 1 day ago

I tried pickling the client like @Aadarsh131 suggested, and I also tried saving the session details like @tradeautumn suggested. In both cases I am able to save session but order placement does not work.

This seems to be in line with what @geek-coder noted, order placements are not working when reusing the session by these methods. Every order placement is requiring a fresh session though reinitiation using OTP or MPIN. This is really annoying, and more importantly it would adversely affect the speed of order placement --- having an extra login / client initiation step before every order placement feels too burdening. I haven't faced this with other APIs, there has to be a better way as APIs are supposed to enable efficient order placement.

Is there an official way to save session and reuse it such that every order placement does not require a fresh initiation using OTP/MPIN? Kindly share if anyone knows of a way to do this.