iqoptionapi icon indicating copy to clipboard operation
iqoptionapi copied to clipboard

wee lost candles now :(

Open remarco opened this issue 7 years ago • 52 comments

something changed. no more candles data :( i dont know what. any patch for this????

for me write error

Traceback (most recent call last): File "C:\iqoptionbot\bot_data.py", line 22, in for candles in data: TypeError: 'NoneType' object is not iterable

2018-04-10 23:20:24,581 {"name":"timeSync",

remarco avatar Apr 10 '18 20:04 remarco

from 6:30 pm it does not work...

luidelia avatar Apr 10 '18 22:04 luidelia

fix it pls

suddar avatar Apr 11 '18 03:04 suddar

I not a programmer and i think i cant solve this.... wee can only wait for someone who can....

remarco avatar Apr 11 '18 05:04 remarco

someone has news???

luidelia avatar Apr 11 '18 15:04 luidelia

nop... i tray to find what was changed in candles request but find nothing :( i dont know how to find...

remarco avatar Apr 11 '18 21:04 remarco

I'm new with this code, but I have a first solution to solve this problem:

Sorry, the following Instruction is for another iqoption repo

Please see the messages below!

SeanStayn avatar Apr 12 '18 00:04 SeanStayn

We agree that the request and response has changed, but not with your changes to the api.py file, maybe you use other api? This is api.py

luidelia avatar Apr 12 '18 10:04 luidelia

You are right, SORRY, I use this repo: https://github.com/bitte-ein-bit/IQOption-Api

But the new request is the following: {"name":"sendMessage","request_id":"15","msg":{"name":"get-candles","version":"2.0","body":{"active_id":1,"size":60,"to":1523488183,"count":1}}}

  • active_id is the market id
  • size is the size of the candle in seconds

SeanStayn avatar Apr 12 '18 10:04 SeanStayn

SeanStayn ty for info... i no time to make changes now but tomorow i check this solution... ty for info:)

remarco avatar Apr 12 '18 10:04 remarco

I have taken a look at this repo, you must change the request in this file: https://github.com/n1nj4z33/iqoptionapi/blob/master/iqoptionapi/ws/chanels/candles.py

And if you want to use the request_id as well, you have to change the send_websocket_request in the api.py. You can try to change the following code..

def send_websocket_request(self, name, msg):
        """Send websocket request to IQ Option server.
        :param str name: The websocket request name.
        :param dict msg: The websocket request msg.
        """
        logger = logging.getLogger(__name__)

        data = json.dumps(dict(name=name,
                               msg=msg))
        logger.debug(data)
        self.websocket.send(data)

... to this code (I have not tested it, but it should work:

def send_websocket_request(self, name, msg, request_id=None):
        """Send websocket request to IQ Option server.
        :param str name: The websocket request name.
        :param dict msg: The websocket request msg.
        """
        logger = logging.getLogger(__name__)
        if request_id is None:
             data = json.dumps(dict(name=name,
                               msg=msg))
        else:
              data = json.dumps(dict(name=name,request_id=request_id
                               msg=msg))
        logger.debug(data)
        self.websocket.send(data)

AND the response message comes here in on_message: https://github.com/n1nj4z33/iqoptionapi/blob/master/iqoptionapi/ws/client.py

(!message in this case doesn't contain a data attribute anymore. It has changed to "candles"!)

elif message["name"] == "candles":
            self.api.candles.candles_data = message["msg"]["data"]

SeanStayn avatar Apr 12 '18 10:04 SeanStayn

SeanStayn, thanks for the quick reaction. I have now modified my code accordingly (I'm using harwees API (https://github.com/harwee/IQOption-Api/issues), and I am recieving a message, but some things about the reply are different if I see it correctly:

{ u'msg': { u'candles': [{u'from': 1523537640, u'min': 1.23246, u'max': 1.232645, u'volume': 0, u'to': 1523537700, u'close': 1.2325, u'open': 1.2326, u'id': 168315}]}, u'status': 2000, u'name': u'candles', u'request_id': u'15'}

it seems like the active_id property (the market index) does not get send anymore. Do I have to map the request id to marketplaces or is there a more convenient way?

codeChaba avatar Apr 12 '18 13:04 codeChaba

Try on client.py: self.api.send_websocket_request('subscribeMessage', {"name":"candle-generated","params":{"routingFilters":{"active_id":1,"size":60}}})

In all time returns this: {"name":"candle-generated","msg":{"active_id":1,"size":60,"at":1523538897029933427,"from":1523538840,"to":1523538900,"id":168335,"open":1.231655,"close":1.231865,"min":1.231655,"max":1.23189,"ask":1.232005,"bid":1.231725,"volume":0}}

ghost avatar Apr 12 '18 13:04 ghost

warleyolf, does the message you mention subscribe to regular updates (like does the api automatically send the values each time a new candle finishes)?

codeChaba avatar Apr 12 '18 13:04 codeChaba

Okay, these are two different methods..

  1. The following request gets a specific number of candles with a specific time:{"name":"sendMessage","request_id":"15","msg":{"name":"get-candles","version":"2.0","body":{"active_id":1,"size":60,"to":1523488183,"count":1}}}

  2. The following request subscribes the canldes, so you get the newest candle: {"name":"subscribeMessage", "msg": {"name":"candle-generated","params":{"routingFilters":{"active_id":1,"size":60}}}

The question is what you want.. Do you need the last 100 candles for analyzing or something else OR do you need the newest candle, to see the current market value?!

SeanStayn avatar Apr 12 '18 14:04 SeanStayn

thank you for your quick answer. I actually kinda need both and I wan't aware of 2. being a thing, thats pretty cool!

what I was asking before is, with 1. the response does not specify the active_id of the requested candle data anymore, like it did before the update. Am I right? I currently use the request id parameter as a substitute for that (by setting the request_id to the marketplace_id when I send the request message). Seems to work so far

codeChaba avatar Apr 12 '18 14:04 codeChaba

what I was asking before is, with 1. the response does not specify the active_id of the requested candle data anymore, like it did before the update. Am I right?

If I understand it right, yes! But perhaps, IQO will change this in the next days!?

SeanStayn avatar Apr 12 '18 15:04 SeanStayn

Ty @SeanStayn but for me not working with this repo, @remarco have you tried?

luidelia avatar Apr 13 '18 09:04 luidelia

bad lyck :( my knowledge is insufficient

remarco avatar Apr 13 '18 11:04 remarco

Hi @SeanStayn is it possible for you to repost the instructions for the https://github.com/bitte-ein-bit/IQOption-Api repo? That would be much appreciated.

kazi308 avatar Apr 14 '18 10:04 kazi308

ok I got it to work correctly, I am using a different repository, but maybe this helps you guys as well:

The websocket api communicates with the IQoption server using JSON-Messages. In the recent update, the message format for the message you need to send to request candle data changed. @kazi308 Im not using the bitte-ein-bit version, but this should work either way:

to send the request for new candles, use this function:

def update_candle_data(self,market_name,interval,count,end_time):
        self.send_socket_message("sendMessage",{"name":"get-candles",
                                                "version":"2.0",
                                                "body":{"active_id":self.instruments_to_id[market_name],  -                                                    
                                                "size":interval,"to":end_time,"count":count}},
                                                  str(self.instruments_to_id[market_name]))

where market_name is given as string, interval marks the candle size (in seconds), count is the number of candles you want and end-time is the last timepoint. the request_id is a parameter that you can assign. Since the new message format for some reason doesn't return the market_id with the candles anymore, I am using the request_id to specify the market name (which works as a workaround). To send the message correctly, I added request_id to the send function as an optional parameter (the functionality stays the same if no third parameter is given:

def send_socket_message(self,name,msg,request_id=None):
        if request_id is None:
             data = dict(name=name, msg=msg)
        else:
              data = dict(name=name,request_id=request_id,msg=msg)
              #print (json.dumps(data))
        self.socket.send(json.dumps(data))

example call would be
api.update_candle_data("EURUSD",60,10,time.time()) for the last 10 60 seconds candles.

For the message to be recieved correctly, add a member variable to store them, directly under class IQOption: candle_data={}

then go into the on_socket_message() function and add:

 elif message["name"] == "candles":
            self.parse_candles_message(message["msg"],int(message["request_id"]))

now just add the parse_candles_message(...) function:

def parse_candles_message(self,message,market_id):  
        self.__latest_candles_data = message["candles"]
        duration=message["candles"][0]["to"]-message["candles"][0]["from"]
        market_name = self.id_to_instruments[market_id]
        if market_name in self.candle_data:
            self.candle_data[market_name][duration] = message["candles"]
        else:
            self.candle_data[market_name] = {duration:message["candles"]}

this is what worked for me

codeChaba avatar Apr 14 '18 14:04 codeChaba

@kazi308:

The problem: The request AND the response for candles has changed. The very stupid think is, that the response doesn't contain the market id anymore. My solution is to put the market id as request id into the request and get the request id back in the response and with this the market id..

One solution:

  1. Replace your update_candle_data in the api.py file with the following code:
def update_candle_data(self,market_name,interval,start_time,end_time):
        """
            interval (seconds)
            start_time (integer timestamp) 
            end_time (integer tiestamp)
        """
        count = int((end_time-start_time)/interval)+1
        #{{"name":"get-candles","version":"2.0","body":{"active_id":1,"size":60,"to":1523488183,"count":1}}}
        marketId = self.instruments_to_id[market_name]
        self.send_socket_message("sendMessage", {"name": "get-candles", "version": "2.0", "body": {"active_id":marketId,"size":interval,"to":end_time,"count":count}}, "{}".format(marketId))
  1. Replace the following code in the on_socket_message method in the api.py file:
elif messagename == "candles":
            self.parse_candles_message(message)
  1. Replace your parse_candles_message in the api.py file with the following code:
def parse_candles_message(self,message):
        self.__latest_candles_data = message["msg"]["candles"]
        market_name = self.id_to_instruments[int(message["request_id"])]
        duration = message["msg"]["candles"][-1]['to'] - message["msg"]["candles"][-1]['from']
        if market_name in self.candle_data:
            self.candle_data[market_name][duration] = message["msg"]["candles"][:-1]
        else:
            self.candle_data[market_name] = {duration:message["msg"]["candles"][:-1]}
  1. Replace your send_socket_message in the api.py file with the following code:
 def send_socket_message(self, name, msg, msg_id=None, log=True):
        if msg_id is None:
            msg_id = "{}".format(randint(0, 1000))
        data = {"name": name, "request_id": msg_id, "msg": msg}
        if log:
            self.logger.debug("send_socket_message: {0}".format(data))
            self.socket.send(json.dumps(data))
  1. Add the following line at the top of the api.py file: from random import randint

  2. This is an example code, to see how you can access the candle data:

# last 10 candles with an interval of 10 seconds
api.update_candle_data('EURUSD',10,int(time.time())-100,int(time.time()))
time.sleep(1)
lastCandles = api.candle_data['EURUSD'][10]
for candle in lastCandles:
     print(candle['from'])
     print(candle['to'])
     print(candle['open'])
     print(candle['close'])
     print(candle['max'])
     print(candle['min'])
  1. You may have to do the formatting of the code yourself (indenting)

SeanStayn avatar Apr 14 '18 14:04 SeanStayn

Hi @codeChaba and @SeanStayn, thank you for the information. I manged to get it working using codeChaba code. I would like to know how to enable websocket debug?

kazi308 avatar Apr 15 '18 14:04 kazi308

@kazi308 what I did is just put a print message in the functions that send and receive messages, in order to see exactly what the format is that gets send out and received. Actually it's pretty cool because there are a lot of messages that my client just ignores: leaderboards, commission info, etc.

kazi308 [email protected] schrieb am So., 15. Apr. 2018, 16:12:

Hi @codeChaba https://github.com/codeChaba and @SeanStayn https://github.com/SeanStayn, thank you for the information. I manged to get it working using codeChaba code. I would like to know how to enable websocket debug?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/n1nj4z33/iqoptionapi/issues/88#issuecomment-381409718, or mute the thread https://github.com/notifications/unsubscribe-auth/AkTjfmgCbkdhnCPAWXofZK36YtsgQ9vAks5to1VbgaJpZM4TO8Al .

codeChaba avatar Apr 15 '18 14:04 codeChaba

@kazi308:

I'm using Chrome:

  1. Go to IqOptions trade room
  2. Open DevTools by pressing Command+Option+I (Mac) or Control+Shift+I (Windows, Linux). This shortcut opens the Console panel.
  3. Select the "Network" tab
  4. Select the "WS" tab in the "Network" tab
  5. Refresh the page (F5)
  6. After loading you can see the open web sockets. Double-click on the web socket and you can see what you want! :)

Have fun!

SeanStayn avatar Apr 15 '18 15:04 SeanStayn

Thanks for the info guys!

kazi308 avatar Apr 16 '18 11:04 kazi308

Sostituendo questo data = {"name": "get-candles", "version": "2.0", "body": {"active_id":active_id,"size":duration,"to":(self.api.timesync.server_timestamp - (duration * amount)) ,"count":amount}}

in candles.py funziona, ma la risposta è ancora grezza, riesco a recuperare i dati elaborandoli nel mio script.

luidelia avatar Apr 16 '18 15:04 luidelia

I not understand where make the changes :( @kazi308 how you did it? can you write files where i must made changes ?

remarco avatar Apr 16 '18 16:04 remarco

thank @SeanStayn I fix iqoptionapi https://github.com/Lu-Yi-Hsun/iqoptionapi

run on python3 success sample code

from iqoptionapi.api import IQOptionAPI
import datetime
import time
import logging
logging.basicConfig(format='%(asctime)s %(message)s')

api = IQOptionAPI("iqoption.com", "email","password")

api.connect()
time.sleep(1.5)
print ('Your current blance is: {:.2f}'.format(api.profile.balance))

api.buy(1, 1, "turbo", "call")
api.getcandles(1, 1, 3)
            #getcandles(ACTIVES,interval,count)
            #ACTIVES:look constants.py file
            #interval: time interval
            #count:how many candles you want to get from now to past
#somehow we need that wait. Don't ask me why. Otherwise we have no data
time.sleep(2)
data = api.candles.candles_data

print(data)

Lu-Yi-Hsun avatar Apr 16 '18 17:04 Lu-Yi-Hsun

@SeanStayn and now change your password :)

remarco avatar Apr 16 '18 17:04 remarco

@remarco please forget it QQ

Lu-Yi-Hsun avatar Apr 16 '18 17:04 Lu-Yi-Hsun