Python med public feed

Added by Anonymous over 7 years ago

Hej

Jag försöker förstå hur jag ska få tag på datan i python från den publika feeden. I de tre sista raderna försöker jag göra subscribe. Men jag förstår inte var jag ska skicka kommandot. Det gör ju också att jag inte vet om kommandot är rätt. Kan ni ge en hint på hur detta borde fungera?

@def f2():
global headers, params, session_key, auth, account_id
headers = {"Content-type": "application/x-www-form-urlencoded","Accept": "application/json",'Accept-Language':'en'}
params = {'service': 'NEXTAPI', 'auth': hash}
r = requests.get(URL, headers = headers)
print_json(json.loads(r.text))

r=requests.post(URL + '/login',data=params, headers=headers)
print_json(json.loads(r.text))
rj=json.loads(r.text)
session_key=rj['session_key']
auth = (session_key,session_key)
print_json(req('accounts'))
account_id = req('accounts')[0]['id'] ##
##Modification
params = {"cmd":"subscribe", "args":{"t":"price", "i":"101", "m":11}}
r=requests.post(URL + '/',data=params, headers=headers)
print_json(json.loads(r.text))
@

Replies (18)

RE: Python med public feed - Added by Björn over 7 years ago

Hej!

Privat och publik feed hanteras inte med HTTP utan går över vanliga socketar krypterad med SSL.
I svaret på login får du information om den publika respektive den privata feeden: adress, port och huruvida den är krypterad (vilket den är).
Du behöver alltså koppla upp dej mot angivna SSL-krypterade socketar och skicka och ta emot JSON-data som ren text.

RE: Python med public feed - Added by Anonymous over 7 years ago

Finns det något exempel på hur detta ska gå till?

RE: Python med public feed - Added by Anonymous over 7 years ago

Detta är koden jag försöker köra.

@
import socket, ssl, pprint

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

ssl_sock = ssl.wrap_socket(s, ca_certs="NEXTAPI_TEST_public.pem", cert_reqs=ssl.CERT_OPTIONAL)

ssl_sock.connect(('pub.api.test.nordnet.se', 443))

print repr(ssl_sock.getpeername())
print ssl_sock.cipher()
print pprint.pformat(ssl_sock.getpeercert())

ssl_sock.write('{cmd:subscribe, args:{t:price, i:101, m:11}}')

data = ssl_sock.read()

ssl_sock.close()
@

File "workspace/api/nordnet/Test.py", line 8, in <module>
ssl_sock.connect(('pub.api.test.nordnet.se', 443))
File "/usr/lib/python2.7/ssl.py", line 322, in connect
self._real_connect(addr, False)
File "/usr/lib/python2.7/ssl.py", line 305, in _real_connect
self.ca_certs, self.ciphers)
ssl.SSLError: [Errno 0] _ssl.c:340: error:00000000:lib(0):func(0):reason(0)

Dvs. det går fel på ssl_sock.connect()

Men det gör ju också att jag inte vet om anropet fungerar korrekt sen. Några ledtrådar?

RE: Python med public feed - Added by Martin over 7 years ago

Jag tror felet här är att NEXTAPI_TEST_public.pem inte är en giltig certifikatfil. Om du kollar i den står det

BEGIN PUBLIC KEY

Det borde stå

BEGIN CERTIFICATE

Jag har fastnat på samma sak själv. Koden du använder är identisk med det jag försöker göra (socket.socket, ssl.wrap_socket, ssl_sock.connect), samma som i Python-manualen för SSL sockets.

Jag har precis postat en ny fråga om detta. Förhoppningsvis är det någon som vet vilken certifikatfil som skall användas.

RE: Python med public feed - Added by Nordnet Simon over 7 years ago

Nej, tyvärr har vi lite dåligt med PHP och Python kunskap, men NEXTAPI_TEST_public.pem har absolut ingenting med SSL att göra.

RE: Python med public feed - Added by Anonymous over 7 years ago

Det är extremt frustrerande att inte kunna få lite mer hjälp när det gäller detta. Men nu är jag såhär långt. Finns det någon som kan se om jag har något uppenbart fel här?

def PrivateConnect(self):
global context

context = M2Crypto.SSL.Context() 
if sys.platform.startswith('linux'):
context.load_verify_info(capath="/tmp")
elif sys.platform.startswith('darwin'):
context.load_verify_info(cafile="NEXTAPI_TEST_public.pem")
else:
print "Unknown platform, bail!"
exit(1)
context.set_allow_unknown_ca(True)
context.set_verify(M2Crypto.SSL.verify_none,9)
conn = M2Crypto.SSL.Connection(context) 
socket.setdefaulttimeout(2.0)
conn.set_socket_read_timeout(M2Crypto.SSL.timeout(sec=2))
conn.set_socket_write_timeout(M2Crypto.SSL.timeout(sec=2))
conn.connect((self.prvHostName,self.prvPort))
loginCmd = '{"cmd":"login", "args":{ "session_key":"%s", "service":"NEXTAPI"}}' % self.session_key
print (loginCmd)
conn.send(loginCmd)
mystr = conn.recv(1024)
print (mystr)
subscribe = '{"cmd":"subscribe", "args":{"t":"trade", "m":11, "i":"101"}}'
print(subscribe)
#conn.send('{cmd:subscribe, args:{t:price, i:101, m:11}}')
conn.send(subscribe)
mystr = conn.recv(1024)
print (mystr)

Det som jag loggar ut ger följande. Som ni kan se så ger varje recv None tillbaka. Vilket väl innebär att servern inte svarar med någon data.

URL: https://api.test.nordnet.se/next/1 ************
country:SE
expires_in:300
environment:test
private_feed
encrypted:True
hostname:priv.api.test.nordnet.se
port:443
session_key:a6c501a86173ae5cc480bb36452eb7ac7b80c9e7
public_feed
encrypted:True
hostname:pub.api.test.nordnet.se
port:443 {"cmd":"login", "args":{ "session_key":"a6c501a86173ae5cc480bb36452eb7ac7b80c9e7", "service":"NEXTAPI"}}
None {"cmd":"subscribe", "args":{"t":"trade", "m":11, "i":"101"}}
None

RE: Python med public feed - Added by Nordnet Simon over 7 years ago

Hej, prova att lägg till newline efter loginCmd = '{"cmd":"login", "args":{ "session_key":"%s", "service":"NEXTAPI"}}' % self.session_key (det kan ju vara så att Python gör det automagiskt).

Efter det loopa och läs det som kommer på feeden under 1 minut. Blir du nerkopplad så är det fel på det som skickas in. Om du under den minuten får heartbeats från feeden så är du uppkopplad.

RE: Python med public feed - Added by Anonymous over 7 years ago

heartbeat='{"cmd":"heartbeat","args":{}}'

while (1):
conn.send(heartbeat)
mystr = conn.recv(1024)
print (mystr)

Gjorde en liten loop och efter 5-6 rundor på heartbeat anropet så får jag
File "/usr/lib/python2.7/site-packages/M2Crypto/SSL/Connection.py", line 205, in _write_bio
return m2.ssl_write(self.ssl, data, self._timeout)
M2Crypto.SSL.SSLError: (32, 'Broken pipe')

Så jag antar att det inte får rätt..

RE: Python med public feed - Added by Anonymous over 7 years ago

Så lite mer tester. Det verkar från php tråden som den vill ha in en json.

En liten kodändring sen verkar programmet rulla utan att bli avbrutet men fortfarande ingen vettig data.

heartbeat='{"cmd":"heartbeat","args":{}}\n'
cmd = json.dumps(heartbeat)
print (cmd)

while (1):
conn.send(cmd)
mystr = conn.recv(1024)
print(mystr)

--------------------------
Log

"{\"cmd\":\"login\", \"args\":{ \"session_key\":\"acc7cdd359e5f9ed33839c16be25035bc3b482e5\", \"service\":\"NEXTAPI\"}}\n"
None
"{\"cmd\":\"subscribe\", \"args\":{\"t\":\"price\", \"m\":\"30\", \"i\":\"1869\"}}\n"
"{\"cmd\":\"heartbeat\",\"args\":{}}\n"
None
None
None
None
None
None
None
None
None
None
None
None
None
None
None
None
None

RE: Python med public feed - Added by Nordnet Simon over 7 years ago

Hej, tvärtom du ska bara lyssna efter heartbeats aldrig skicka.

Så du ska bara göra ungefär så här (med disclaimer för att jag inte kan Python) i ungefär 1 minut.


while (1):
            mystr = conn.recv(1024)
            print(mystr)


Om du inte får några heartbeats så är det något annat fel. Kan man kolla att conn är i korrekt state?

RE: Python med public feed - Added by Anonymous over 7 years ago

Jag har provat båda varianterna. Men det ger samma resultat dvs. none.

RE: Python med public feed - Added by Nordnet Simon over 7 years ago

Då är det svårt att säga vad som är fel.

Feeden fungerar så här
- Om du inte skickar in något inom några sekunder så kopplar feeden ner.
- Om första meddelandet du skickar in inte är login eller att det är något fel på det meddelandet så kopplar feeden ner.
- Om första meddelandet är ett riktigt login så är feeden uppe - den kommer då att skicka heartbeat med jämna mellanrum.

Så efter det att du har skickat in login så måste du kolla vilken state conn är.

RE: Python med public feed - Added by Martin over 7 years ago

Tjenare, här är lite Python-kod som hjälp på traven. Funkar finfint för mig. Lycka till! :-)

  1. Create SSL-wrapped socket
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    ssl_socket = ssl.wrap_socket(s)
  1. Connect to socket
    ssl_socket.connect((self.public_feed, 443))
  1. Send session key
    cmd = {"cmd": "login", "args": {"session_key": self.session_key0}}
    num_bytes = ssl_socket.send(_dict_to_json(cmd) + "\n")
    print "Session key sent (%d bytes)" % num_bytes
  1. Subscribe to stocks
    for (m, i) in stocks:
    cmd = {"cmd": "subscribe", "args": {"t": "price", "m": m, "i": str(i)}}
    num_bytes = ssl_socket.send(_dict_to_json(cmd) + "\n")
    print "Subscription request sent for m = %d and i = %d (%d bytes)" % (m, i, num_bytes)
  1. Read stream
    print "Reading stream"
    while True:
    output = ssl_socket.recv()
    print output

RE: Python med public feed - Added by Martin over 7 years ago

Hmm... formateringen försvann och kommentarer förvandlades till "1." i posten ovan men du fattar...

RE: Python med public feed - Added by Nirdharsh over 7 years ago

Below approach does work for me. (Note! very similar to Martin's suggestion, however additions are some socket logs, a specific dictionary to json conversion operation, & socket closing operation):

1. Create SSL-wrapped socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ssl_socket = ssl.wrap_socket(s)

2. Connect to socket

  1. Note that HOSTNAME & PORT are REST provided public_feed's hostname & port number
  2. For e.g. HOSTNAME = pub.api.test.nordnet.se & PORT = 443
    ssl_socket.connect((HOSTNAME, PORT))
    print repr(ssl_sock.getpeername())
    print ssl_sock.cipher()

3. Send session key

cmd = {"cmd":"login", "args":{"session_key":session_key, "service":"NEXTAPI"}}
num_bytes = ssl_socket.write(json.dumps(cmd) + "\n")
print "Session key sent (%d bytes)" % num_bytes

4. Subscribe to a stock

market = 11
instrument = "101"
cmd = {"cmd":"subscribe", "args":{"t":"price", "m":market, "i":instrument}}
num_bytes = ssl_socket.send(json.dumps(cmd) + "\n")
print "Subscription request sent for market = %d and instrument = %s (%d bytes)" % (market, instrument, num_bytes)

5. Read stream once and close socket connection

print "Reading stream"
output = ssl_socket.read()
print output
  1. Note that you need to close the underlying socket, not the SSL object.
    print "Closing socket connection..."
    del ssl_socket
    s.close()

RE: Python med public feed - Added by Martin over 7 years ago

Yes, very similar. My _dict_to_json() function is actually just a call to json.dumps().

RE: Python med public feed - Added by Anonymous over 7 years ago

Tackar, ska testa. Kan det vara m2crypto versionen som spökar i min implementation ....?

RE: Python med public feed - Added by Martin over 7 years ago

Jag kör med m2crypto version 0.21.1 (Ubuntu 12.04).

(1-18/18)