Bitcoin Forum
October 06, 2024, 10:22:44 AM *
News: Latest Bitcoin Core release: 28.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: [Solved] Jemand der Python3 Skript korrigiert, biete 0.07BTC Belohnung  (Read 1596 times)
Serpens66 (OP)
Legendary
*
Offline Offline

Activity: 2940
Merit: 1131



View Profile
May 16, 2015, 04:48:12 PM
Last edit: July 15, 2015, 03:41:03 PM by Serpens66
 #1

Gelöst

Hi Smiley

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 Smiley

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.

Mit Cointracking (10% Rabatt) behältst du die Übersicht über all deine Trades und Gewinne. Sogar ein Tool für die Steuer ist dabei Wink                          
Great Freeware Game: Clonk Rage
binance.com hat nun auch SEPA und EUR Paare! Mit dem RefLink bekommst du 5% Rabatt auf die Tradinggebühren!
Sukrim
Legendary
*
Offline Offline

Activity: 2618
Merit: 1007


View Profile
May 17, 2015, 10:54:28 AM
 #2

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.


https://www.coinlend.org <-- automated lending at various exchanges.
https://www.bitfinex.com <-- Trade BTC for other currencies and vice versa.
Serpens66 (OP)
Legendary
*
Offline Offline

Activity: 2940
Merit: 1131



View Profile
May 17, 2015, 11:31:46 AM
 #3

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() )

Mit Cointracking (10% Rabatt) behältst du die Übersicht über all deine Trades und Gewinne. Sogar ein Tool für die Steuer ist dabei Wink                          
Great Freeware Game: Clonk Rage
binance.com hat nun auch SEPA und EUR Paare! Mit dem RefLink bekommst du 5% Rabatt auf die Tradinggebühren!
Sukrim
Legendary
*
Offline Offline

Activity: 2618
Merit: 1007


View Profile
May 17, 2015, 02:35:00 PM
 #4

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.

https://www.coinlend.org <-- automated lending at various exchanges.
https://www.bitfinex.com <-- Trade BTC for other currencies and vice versa.
Serpens66 (OP)
Legendary
*
Offline Offline

Activity: 2940
Merit: 1131



View Profile
May 17, 2015, 05:23:58 PM
 #5

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 Cheesy Nur jetzt komme ich halt nicht weiter, weil ich keine Angabe über Fehler von Yacuna erhalte.
 

Mit Cointracking (10% Rabatt) behältst du die Übersicht über all deine Trades und Gewinne. Sogar ein Tool für die Steuer ist dabei Wink                          
Great Freeware Game: Clonk Rage
binance.com hat nun auch SEPA und EUR Paare! Mit dem RefLink bekommst du 5% Rabatt auf die Tradinggebühren!
Sukrim
Legendary
*
Offline Offline

Activity: 2618
Merit: 1007


View Profile
May 17, 2015, 05:57:07 PM
 #6

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. Sad

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...

https://www.coinlend.org <-- automated lending at various exchanges.
https://www.bitfinex.com <-- Trade BTC for other currencies and vice versa.
Serpens66 (OP)
Legendary
*
Offline Offline

Activity: 2940
Merit: 1131



View Profile
May 17, 2015, 08:13:24 PM
 #7

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. Sad
So war das nicht gemeint ^^ Ich meinte vor deinen Posts allgemein wusste ich das nicht Wink  
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 Smiley

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...

Mit Cointracking (10% Rabatt) behältst du die Übersicht über all deine Trades und Gewinne. Sogar ein Tool für die Steuer ist dabei Wink                          
Great Freeware Game: Clonk Rage
binance.com hat nun auch SEPA und EUR Paare! Mit dem RefLink bekommst du 5% Rabatt auf die Tradinggebühren!
tyz
Legendary
*
Offline Offline

Activity: 3360
Merit: 1533



View Profile
June 20, 2015, 10:46:46 AM
 #8

Das Thema ist schon ein paar Tage alt, aber besteht das Problem noch? Bin nebenberuflich Python Entwickler und könnte dir da weiterhelfen.
Serpens66 (OP)
Legendary
*
Offline Offline

Activity: 2940
Merit: 1131



View Profile
June 20, 2015, 01:46:32 PM
 #9

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 Smiley

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.

Mit Cointracking (10% Rabatt) behältst du die Übersicht über all deine Trades und Gewinne. Sogar ein Tool für die Steuer ist dabei Wink                          
Great Freeware Game: Clonk Rage
binance.com hat nun auch SEPA und EUR Paare! Mit dem RefLink bekommst du 5% Rabatt auf die Tradinggebühren!
Serpens66 (OP)
Legendary
*
Offline Offline

Activity: 2940
Merit: 1131



View Profile
July 15, 2015, 03:40:06 PM
 #10

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 Smiley

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

Mit Cointracking (10% Rabatt) behältst du die Übersicht über all deine Trades und Gewinne. Sogar ein Tool für die Steuer ist dabei Wink                          
Great Freeware Game: Clonk Rage
binance.com hat nun auch SEPA und EUR Paare! Mit dem RefLink bekommst du 5% Rabatt auf die Tradinggebühren!
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!