Bitcoin Forum

Local => Suche => Topic started by: Serpens66 on May 16, 2015, 04:48:12 PM



Title: [Solved] Jemand der Python3 Skript korrigiert, biete 0.07BTC Belohnung
Post by: Serpens66 on May 16, 2015, 04:48:12 PM
Gelöst

Hi :)

Ich möchte eine API Anbindung an Yacuna.com in Python3.
Hier deren API Seite mit Beschreibung was wie gefordert wird: http://docs.yacuna.com/api/

Ich habe mich schon selbst so gut es geht daran versucht und auch ein wenig Hilfe vom Support bekommen. Leider kann dieser aber kein Python, weshalb sie wohl auch mit ihrer Weisheit am Ende sind.. Zusätzlich gibt es das Problem, dass man bei einem Fehler von Yacuna nur sinngemäß "fehler" zurückbekommt, ohne irgendeinen Hinweis darauf, was denn nun nicht stimmt.

So sieht mein Skript bisher aus (key, secret und wallet Ids im init müssen natürlich durch korrekte werte ersetzt werden):
Code:
import json
import requests
import sys
import hmac
import hashlib
import time
from requests import Request, Session


class YacunaAPI:

    def load_key(self, path): # falls key nicht in skript speichern, hiermit laden
        f = open(path, "r")
        self.key = f.readline().strip()
        self.secret = f.readline().strip()
    
    def __init__(self, key = '', secret = ''):
        self.key = "abc"
        self.secret = "123"
        self.uri = 'https://yacuna.com'
        self.apiversion = '1'
        self.walletId = "AAA" # die ganzen Walletdaten bekommt man über die GetWallet Funktion und können dann hardgecodet werden (glaub ich)
        self.walletAccountIdEUR = "BBB"
        self.walletAccountIdXBT = "CCC"

        
    def CalculateURLPath(self, method, params):
        urlpath = '/api/' + self.apiversion + '/' + method + '/'
        s = Session()
        req = Request('POST', self.uri + urlpath, data=params) # für den body ists egal ob post oder get
        prepped = s.prepare_request(req)
        aufgeteilt = prepped.body.split("&") # bei & getrennt
        aufgeteilt2 = sorted(aufgeteilt) # und alpabetisch sortiert
        neu = "?"  # startet mit einem ?
        for element in aufgeteilt2:
            neu = neu + element + "&" # elemente werden mit einem & dazwischen wieder zusammengesetzt
        neu = neu[0:len(neu)-1] # das letzte & Zeichen abschneiden
        return(urlpath + neu)
        
    def query_call(self, method, public=0, get=0, params={}):
        print("")
        DetailedUrlPath = self.CalculateURLPath(method, params)
        print(DetailedUrlPath) # zur überprüfung mal printen..
        print("")
        if get:
            if public:
                urlpath = '/api/' + self.apiversion + '/' + method + '/'
                return (requests.get(self.uri + urlpath, params=params,timeout=30).json() )
            else:
                urlpath = '/api/' + self.apiversion + '/' + method + '/'
                nonce = str(int(1000*time.time()))
                string = nonce + "@" + self.secret + "@GET@" + DetailedUrlPath
                encoded = string.encode()
                signature = hashlib.sha512(encoded).hexdigest()
                signature = nonce + "T" + signature
                print(signature)
                print("")
                headers = {
                    "Api-Token-Id": self.key,
                    "Api-Token": signature,
                    "Api-Token-OTP": ""
                    }
                return (requests.get(self.uri + urlpath, params=params,headers=headers,timeout=30).json() )
        else:
            if public:
                urlpath = '/api/' + self.apiversion + '/' + method + '/'
                return (requests.post(self.uri + urlpath, params=params,timeout=30).json() )
            else:
                urlpath = '/api/' + self.apiversion + '/' + method + '/'
                nonce = str(int(1000*time.time()))
                string = nonce + "@" + self.secret + "@GET@" + DetailedUrlPath
                encoded = string.encode()
                signature = hashlib.sha512(encoded).hexdigest()
                signature = nonce + "T" + signature
                print(signature)
                print("")
                headers = {
                    "Api-Token-Id": self.key,
                    "Api-Token": signature,
                    "Api-Token-OTP": ""
                    }
                return (requests.post(self.uri + urlpath,  params=params,headers=headers,timeout=30).json() )

    def GetWallet(self,currency=0): # gibt alle möglichen Wallet infos, inklusive aller Balances aus
        method = 'wallet/get'  
        if currency:
            Wallet = self.query_call(method,0,1,{"currency":currency})
        else:
            Wallet = self.query_call(method,0,1)
        return(Wallet)
            
    def OrderBook(self, currency1, currency2):# getting the full orderbook
        method = "orderbook/get"    # zb https://yacuna.com/api/1/orderbook/get/EUR/XBT
        Orders = self.query_call(method,0,1,{"currency1":currency1,"currency2":currency2})
        return Orders  # Fehlerprüfung in eigenen Funktionen
        
    def CancelOrder(self, ID):
        method = "order/cancel"    
        Cancel = self.query_call(method,0,0,{"orderId":ID})
        return Cancel  # Fehlerprüfung in eigenen Funktionen

    def CreateOrder(self, currency1, currency2, type, amount, price):
        method = "order/create"    
        # es werden immer btc gekauft/verkauft, also walletid XBT
        if type=="buy":
            tradeOrderType="BuyLimit"
            buyAmount = amount
            buyCurrency = "XBT"
            priceLimitCurrency = "EUR"
            priceLimitAmount = price
            Create = self.query_call(method,0,0,{"currency1":currency1,"currency2":currency2,"walletAccountId":self.walletAccountIdXBT,"tradeOrderType":tradeOrderType,"buyAmount":amount,"buyCurrency":buyCurrency,"priceLimitCurrency":priceLimitCurrency,"priceLimitAmount":priceLimitAmount})
        elif type=="sell":
            tradeOrderType="SellLimit"
            sellAmount = amount
            sellCurrency = "XBT"
            priceLimitCurrency = "EUR"
            priceLimitAmount = price
            Create = self.query_call(method,0,0,{"currency1":currency1,"currency2":currency2,"walletAccountId":self.walletAccountIdXBT,"tradeOrderType":tradeOrderType,"sellAmount":amount,"sellCurrency":sellCurrency,"priceLimitCurrency":priceLimitCurrency,"priceLimitAmount":priceLimitAmount})
        else:
            raise AssertionError("Ungültiger kauf/verkauftype in YacunaAPI createorder.")
        return Create  # Fehlerprüfung in eigenen Funktionen    
                
    def OrderList(self, tradeOrderStatus, count=30): # tradeOrderStatus  == "Confirmed" .. gibt noch mehr sortierungsmöglichkeiten, siehe api doku
        method = "order/list"
        List = self.query_call(method,0,1,{"walletAccountId":self.walletAccountIdEUR,"tradeOrderStatus":tradeOrderStatus,"count":count,"startWith":0})
        return List  # Fehlerprüfung in eigenen Funktionen    

Ich glaube jeder Pythonprogrammierer würde mir nun erstmal einen Vortrag halten, wie unschön dieses Skript ist und so weiter. Das ist der Grund weshalb ich die Frage nicht im Pythonforum stelle.. habe da keine guten erfahrungen gemacht.
Es ist mir egal wie es aussieht, hauptsache es tut was es soll :)

Jedenfalls möchte ich, wie man sieht, das Modul "requests" verwenden, welches hier beschrieben wird:
http://docs.python-requests.org/en/latest/

Ich glaube der GetWallet Aufruf funktioniert sogar schon. Probleme gibt es mit anderen Aufrufen, wie CreateOrder bzw CancelOrder (also den Post-Anfragen).

Zum austesten ob eure Korrektur funktioniert würde ich empfehlen einfach schnell einen Yacuna Account aufzumachen und dort API Key + Secret zu generieren.  Ich glaube dazu muss man sich nicht verifizieren, sollte also kein Problem sein.


Title: Re: Jemand der Python3 Skript korrigiert, biete 0.07BTC Belohnung
Post by: Sukrim on May 17, 2015, 10:54:28 AM
Lass einfach mal pylint drüber laufen, das spuckt dir dann schon aus, was du erstmal ausbessern solltest - von unbenutzten Variablen + Imports, fehlenden Docstrings und auch schlimmeren Problemen, wie z.B. dem Umdefinieren von eingebauten Keywords wie "type" in der CreateOrder Funktion. In einer halben Stunde maximal hast du die "Formfehler" beseitigt und danna uch ein weitaus übersichtlicheres Programm, das du auch leichter debuggen lassen kannst, weil es auch andere verstehen können.

Ist ja ganz nett, dass du nicht auf Konventionen zurückgreifen willst, allerdings ist das Ding da ziemlich konfus geschrieben und recht uneinheitlich, also muss man sich viel tiefer einarbeiten als die paar Euro rechtfertigen würden imho.



Title: Re: Jemand der Python3 Skript korrigiert, biete 0.07BTC Belohnung
Post by: Serpens66 on May 17, 2015, 11:31:46 AM
Lass einfach mal pylint drüber laufen, das spuckt dir dann schon aus, was du erstmal ausbessern solltest - von unbenutzten Variablen + Imports, fehlenden Docstrings und auch schlimmeren Problemen, wie z.B. dem Umdefinieren von eingebauten Keywords wie "type" in der CreateOrder Funktion. In einer halben Stunde maximal hast du die "Formfehler" beseitigt und danna uch ein weitaus übersichtlicheres Programm, das du auch leichter debuggen lassen kannst, weil es auch andere verstehen können.

Ist ja ganz nett, dass du nicht auf Konventionen zurückgreifen willst, allerdings ist das Ding da ziemlich konfus geschrieben und recht uneinheitlich, also muss man sich viel tiefer einarbeiten als die paar Euro rechtfertigen würden imho.



also kannst du python3?
Ich bin mir relativ sicher, dass alles richtig ist, bis auf den post request.  Also könntest du vllt zumindest schauen, ob dies so funktionieren sollte?
Das ist zumindest der Teil den ich noch nicht verstehe:
Code:
        encoded = string.encode()
        signature = hashlib.sha512(encoded).hexdigest()
        headers = {
                    "Api-Token-Id": self.key,
                    "Api-Token": signature,
                    "Api-Token-OTP": ""
                    }
        return (requests.post(self.uri + urlpath,  params=params,headers=headers,timeout=30).json() )


Title: Re: Jemand der Python3 Skript korrigiert, biete 0.07BTC Belohnung
Post by: Sukrim on May 17, 2015, 02:35:00 PM
Ich bin mir relativ sicher, dass da einiges an ... Zweifelhaftigkeiten in dem Code steckt.

z.B.:
Code:
def CreateOrder(self, currency1, currency2, type, amount, price):
"type" ist ein reservierter Name in Python.


Der teil den du da nicht verstehst encodiert einen String, generiert einen sha512 Hash darüber und sendet dann einige Daten via der requests Bibliothek, die die Antwort dann als JSON zurückgeben/interpretieren dürfte.
Bis auf einige Probleme mit Variablennamen und Codingstil sehe ich in dem kleinen Beispiel da nichts Ungewöhnliches.


Title: Re: Jemand der Python3 Skript korrigiert, biete 0.07BTC Belohnung
Post by: Serpens66 on May 17, 2015, 05:23:58 PM
Ich bin mir relativ sicher, dass da einiges an ... Zweifelhaftigkeiten in dem Code steckt.

z.B.:
Code:
def CreateOrder(self, currency1, currency2, type, amount, price):
"type" ist ein reservierter Name in Python.


Der teil den du da nicht verstehst encodiert einen String, generiert einen sha512 Hash darüber und sendet dann einige Daten via der requests Bibliothek, die die Antwort dann als JSON zurückgeben/interpretieren dürfte.
Bis auf einige Probleme mit Variablennamen und Codingstil sehe ich in dem kleinen Beispiel da nichts Ungewöhnliches.
Dass type reserviert ist wusste ich nicht, danke, kann ich abändern.

Also um deine Aussage auf meine Hauptfrage zu beziehen:
Du meinst, dass meine request.post anfrage den Anforderungen von Yacuna entspricht ? (wir gehen mal davon aus, dass mein self.uri, mein urlpath, mein params und mein header korrekt sind)

ich bin zb. unsicher, ob ich .hexdigest() anwenden muss oder nur .digest()  .... und ob ich iwo noch hmac oderso anwenden muss

Ich hatte im Bezug aufs Codieren das Skript von Kraken zur Hilfe genommen: https://github.com/veox/python3-krakenex/blob/master/krakenex/api.py
Dort wird halt digest() und hmac verwendet...

Ich gehe davon aus, dass diese ganzen Codierungsbefehle sehr viel Verständnis im Codieren voraussetzen und dass es lange dauern würde, das alles zu verstehen. Da ich das Codieren nur für die Anbindung brauche und sonst nie bei meinen Programmierungen, halte ich es für am effektivsten mich nicht mit dem Codieren zu beschäftigen, sondern es über try and error zu probieren... Bisher hatte das ganz gut geklappt :D Nur jetzt komme ich halt nicht weiter, weil ich keine Angabe über Fehler von Yacuna erhalte.
 


Title: Re: Jemand der Python3 Skript korrigiert, biete 0.07BTC Belohnung
Post by: Sukrim on May 17, 2015, 05:57:07 PM
Quote
Dass type reserviert ist wusste ich nicht, danke, kann ich abändern.

Hättest du, wie zuvor von mir empfohlen, pylint drüber laufen lassen, hättest du das schon gewusst. :(

Quote
Du meinst, dass meine request.post anfrage den Anforderungen von Yacuna entspricht ?
Was Yacuna da für seine API verlangt, weiß ich nicht. Deren Webseite lässt sich ohne Javascript nicht mal laden... und wegen 0.07 BTC fang ich da jetzt auch nicht an, mich durch Dokumentation zu hangeln. Vermutlich wird da was gröber falsch laufen, wenn du nur versuchst, die API von Kraken zu kopieren. https://github.com/yacuna/api hat anscheinend Implementationen in perl und in PHP, es sollte durchaus zu machen sein, ~100 Zeilen perl (https://github.com/yacuna/api/blob/master/perl/Finance-Bitcoin-Yacuna-0.2/lib/Finance/Bitcoin/Yacuna.pm) in Python nachzubauen...


Title: Re: Jemand der Python3 Skript korrigiert, biete 0.07BTC Belohnung
Post by: Serpens66 on May 17, 2015, 08:13:24 PM
Quote
Dass type reserviert ist wusste ich nicht, danke, kann ich abändern.

Hättest du, wie zuvor von mir empfohlen, pylint drüber laufen lassen, hättest du das schon gewusst. :(
So war das nicht gemeint ^^ Ich meinte vor deinen Posts allgemein wusste ich das nicht ;)  
Und ansonsten werde ich mir Pylint mal genauer anschauen... ich tue mich wirklich extreeemst schwer damit, mich den Python Konventionen anzupassen. Habe diesbezüglich auch shcon etliche hitzige Diskussionen im Pythonforum führen müssen. In erster Linie liegt es daran, dass ich lange brauche vorgefertigte Skripte, wie zb das von Kraken nachzuvollziehen. Skripte wie meines kann ich aber sehr schnell nachvollziehen (also vom aufbau her). Deswegen erscheint es für mich unlogisch eine Konvention zu nutzen, die es für mich nur komplizierter macht und deswegen nutze ich sie nicht.    
Früher war mein Code natürlich noch schlimmer. Je mehr ich lerne und verstehe, desto übersichtlicher wird mein Code. Und ich finde, dass das genau der richtige Weg ist. Irgendwann wird mein Code sowohl für mich als auch für andere verständlich sein. Auf diesen Weg wird mir Pylint vllt helfen, also danke für diesen Tipp :)

Quote
Du meinst, dass meine request.post anfrage den Anforderungen von Yacuna entspricht ?
Was Yacuna da für seine API verlangt, weiß ich nicht. Deren Webseite lässt sich ohne Javascript nicht mal laden... und wegen 0.07 BTC fang ich da jetzt auch nicht an, mich durch Dokumentation zu hangeln. Vermutlich wird da was gröber falsch laufen, wenn du nur versuchst, die API von Kraken zu kopieren. https://github.com/yacuna/api hat anscheinend Implementationen in perl und in PHP, es sollte durchaus zu machen sein, ~100 Zeilen perl (https://github.com/yacuna/api/blob/master/perl/Finance-Bitcoin-Yacuna-0.2/lib/Finance/Bitcoin/Yacuna.pm) in Python nachzubauen...
Ich schau mir die tage mal die Perl version an, vllt kann ich daraus ja ein bisschen was ableiten...


Title: Re: Jemand der Python3 Skript korrigiert, biete 0.07BTC Belohnung
Post by: tyz on June 20, 2015, 10:46:46 AM
Das Thema ist schon ein paar Tage alt, aber besteht das Problem noch? Bin nebenberuflich Python Entwickler und könnte dir da weiterhelfen.


Title: Re: Jemand der Python3 Skript korrigiert, biete 0.07BTC Belohnung
Post by: Serpens66 on June 20, 2015, 01:46:32 PM
Das Thema ist schon ein paar Tage alt, aber besteht das Problem noch? Bin nebenberuflich Python Entwickler und könnte dir da weiterhelfen.
Hey, danke dass du dich meldest :)

Ja das Problem besteht noch.
Aus den bisherigen Posts kannst du ja auch glaube ich lesen, worin das Hauptproblem besteht. 

Ich komme noch nicht so ganz mit dem ganzen Codieren und Internetkram klar. Also ich weiß nicht, wann ich was wie codieren muss und welche Befehle ich dafür verwenden muss, z.b .hexdigest() vs digest().

Ich tippe stark darauf, dass genau das in meinem Skript der Hauptfehler ist. Nebenbei gibt es sicherlich einige Dinge, die ein echter Programmierer anders lösen würde, aber in erster Linie kommt es für mich darauf an, dass es funktioniert, egal wie umständlich geschrieben.


Title: Re: Jemand der Python3 Skript korrigiert, biete 0.07BTC Belohnung
Post by: Serpens66 on July 15, 2015, 03:40:06 PM
Ich hab eben nochmal ein wenig rumprobiert und festgestellt, dass alles funktioniert, solange ich keine Zahlen als Parameter übergebe.

Das heißt folgender link, welcher dann in die signature verwandelt wird, funktioniert (ausgedachte walletid):
/api/1/order/list/?tradeOrderStatus=Confirmed&walletAccountId=DFSDFWFS12321231AFDSF

während er nicht mehr funktiniert, wenn ich einen Paramtert zufüge, der eine Zahl beinhaltet, zb.:
/api/1/order/list/?startWith=0&tradeOrderStatus=Confirmed&walletAccountId=DFSDFWFS12321231AFDSF

Habe die Frage nun an den Yacuna Support weitergeleitet, warum Zahlen nicht funzen und denke dass das damit dann alles gelöst wird :)

Vielen dank an diejenigen die sich hier und per PN gemeldet hatten, auch wenn keiner das Problem lösen konnte :D