Ccxt: Einheitlicher Verlauf der Ein- und Auszahlungstransaktionen

Erstellt am 14. Feb. 2018  ·  64Kommentare  ·  Quelle: ccxt/ccxt

Wurde die einheitliche Einzahlungs- und Auszahlungshistorie in irgendeiner implementiert?
der Börsen noch (oder Basisklassen für diese Angelegenheit)? Ich hatte gehofft, einen als Beispiel zu finden.

enhancement

Hilfreichster Kommentar

@kroitor du bist ein fantastisches Beispiel für einen Projektbetreuer 👌, danke für die harte Arbeit (sorry, dass diese Nachricht alle im Thread spammt - aber ich wollte auf jeden Fall _Danke_ sagen).

Alle 64 Kommentare

Wurde die einheitliche Einzahlungs- und Auszahlungshistorie in irgendeiner implementiert?
der Börsen noch (oder Basisklassen für diese Angelegenheit)?

Noch nicht, dies ist der letzte Teil der Unified API. Wir werden diesen Aspekt sofort nach der Deckung der Finanzierungsgebühren (und der Vereinheitlichung aller Gebühren im Allgemeinen, diese Arbeit wird derzeit durchgeführt, wie Sie an den Pull-Anfragen sehen können) ansprechen. 1669, #1814, #1835).

Ihre Beiträge sind wie immer sehr willkommen )

Ich würde vorschlagen, mit ein oder zwei experimentellen Implementierungen für eine oder zwei große Börsen zu beginnen, um einheitliche Strukturen für Ein- und Auszahlungen zu entwickeln. Ich werde sie in Kürze hochladen, damit alle Entwickler von dort aus weitermachen können.

@kroitor Gibt es einen Vorschlag zu dieser Implementierung?

@ZohaibAhmed noch nicht, aber wir denken, dass es der Unified Trades-API ziemlich ähnlich sein sollte ...

Hier ist es:

// returns deposits and withdrawals
fetchTransactions (currency = undefined, since = undefined, limit = undefined, params = {})

// returns deposit transactions
fetchDeposits (currency = undefined, since = undefined, limit = undefined, params = {})

// returns withdrawal transactions
fetchWithdrawals (currency = undefined, since = undefined, limit = undefined, params = {})

Eine Transaktion würde einem Trade ähnlich sehen:

    {
        'info':       { ... },                  // the original decoded JSON as is
        'id':        '12345-67890:09876/54321', // string transaction id
        'txid':      'ddsjfdlskjflksdjfkldsjf', // txid in terms of corresponding currency
        'timestamp':  1502962946216,            // Unix timestamp in milliseconds
        'datetime':  '2017-08-17 12:42:48.000', // ISO8601 datetime with milliseconds
        'currency':  'ETH',                     // currency code 
        'status':    'pending',                 // status of the transaction, "pending", "ok"... to be discussed
        'side':      'deposit',                 // direction of the transaction, 'deposit' or 'withdraw'
        'price':      0.06917684,               // float price in quote currency
        'amount':     1.5,                      // absolute amount of base currency
        'fee': {
            'cost': ..., // we also need to somehow designate if...
            'rate': ..., // ...it is a network fee or the exchange fee or both
        },
        ... ? ...
    },

Aus dem oben Gesagten folgt, dass noch Fragen zu diskutieren sind. Ihre Vorschläge und Anregungen sind willkommen.

@kroitor , das sieht gut aus, abgesehen von den Gebühren. Nicht alle Börsen (zB Bittrex) beinhalten Gebühren in ihrer Auszahlungs-/Einzahlungs-API. Sollen wir das jetzt weglassen?

Ich muss Ein- und Auszahlungen für Binance implementieren.

@ZohaibAhmed hast du das implementiert?
@kroitor hast du eine

Ich möchte damit beginnen, aber keine bereits erledigten Arbeiten duplizieren. Ich möchte auch sicherstellen, dass es der Standard-API entspricht.

Ich kann die Unified Trades-API als Ausgangspunkt modellieren.

@grandmore , ich habe noch nicht mit der Implementierung begonnen.

Ein Haken bei der Arbeit mit Abhebungs-/Einzahlungsdaten besteht darin, dass der Betrag bei Abhebungen positiv oder negativ sein kann. Die aktuelle Handels-API zeigt keine negativen Beträge an, sondern wandelt sie in positive um. Stellen wir sicher, dass wir das zur Spezifikation hinzufügen können.

@ZohaibAhmed Es ist ein interessanter Punkt. Wir verfolgen sie entweder als +/- (Kredit/Lastschrift) oder kennzeichnen sie als Einzahlung/Auszahlung.

Ich werde in ein paar Stunden einen Code auf einen Fork schieben. Ich habe eine Binance-Version erstellt, während ich versuche, mich an die Spezifikation zu halten. Viele der Austauschprogramme verfügen nicht über die erforderliche Finesse, sodass ein Großteil der Arbeit in der Bibliothek erledigt werden muss.

@grandmore

hast du eine spezifikation oder nur was in diesem thread?

Nur was steht in diesem Thread...

Ich werde in ein paar Stunden einen Code auf einen Fork schieben.

Stellen Sie sicher, dass Sie dies sorgfältig lesen: https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how -to-contribute-code

Danke!

@kroitor Ja, was steht in diesem Thread, da es alles gibt. Ebenso wie die Modellierung der anderen Funktionen in der Bibliothek.
Ich habe natürlich die gesamte Dokumentation sowie die CONTRIBUTING.md-Dokumentation gelesen und in den letzten Tagen mit der Bibliothek experimentiert.

Es gibt einige clevere Konzepte in der Bibliothek. Wie auch immer, ich werde auf eine Gabelung drängen, damit es sich nicht direkt auf die Bibliothek auswirkt. Wenn es nützlich ist, können Sie es zusammenführen.

Ich werde es morgen zu einer Gabelung schieben, da ich zu spät bin.

@kroitor Ich habe den ersten Entwurf von Binance auf diesen Fork verschoben: Transactions-for- Withdraw

Ich habe die Auszahlungen und Einzahlungen nur nach dieser Spezifikation erstellt

// returns deposit transactions
fetchDeposits (currency = undefined, since = undefined, limit = undefined, params = {})

// returns withdrawal transactions
fetchWithdrawals (currency = undefined, since = undefined, limit = undefined, params = {})

Die restlichen vereinheitlichten fetchTransactions werde ich tun, nachdem ich einige Fragen geklärt habe.

// returns deposits and withdrawals
fetchTransactions (currency = undefined, since = undefined, limit = undefined, params = {})

Es gibt sehr wenig Kompatibilität von den Börsen, die ich mir ansehe.
Binance-API
Poloniex Api
Coinbase API
GDAX-API

Kraken API hat auch /private/Ledgers mit Kontoverlauf.

Die Ein- und Auszahlungen von fetchMyTrades auf Bitstamp falsch. Ein- und Auszahlungen werden durch das Feld type im Eintrag gekennzeichnet. Ich bin mir nicht sicher, ob sie txid für Krypto-Transaktionen über ihre API bereitstellen, obwohl diese Informationen über die eingeloggte Kontoschnittstelle verfügbar sind.

@kroitor Ich schreibe Code für fetchDeposits & fetchWithdrawals, weil wir sie jetzt brauchen. Ich würde mich an die obige Spezifikation halten. Darf ich diesen Code schreiben und Pull-Requests für einige der Börsen stellen? Glaubst du, du könntest diese Änderungen zusammenführen?

@lfern Ihre Beiträge sind willkommen )

@lfern Ich bin in der gleichen Lage. Muss ich jetzt umsetzen, deshalb habe ich am Wochenende angestarrt.

Ich habe einen funktionierenden Prototyp und vergleiche gerade alle Börsen, um die gemeinsame Datenstruktur zu finden. Nachdem ich fertig war, wollte ich die Form der Daten vorschlagen, die gebräuchlich sein können, und einige Ansätze für einige der Variationen.

Eines der Hauptprobleme, die ich sehe, ist, dass einige der Börsen keine ID-Nummer haben, um die Transaktion eindeutig zu identifizieren. Aus diesem Grund habe ich darüber nachgedacht, einen Hash der gemeinsamen Daten zu erstellen, um einen Schlüssel zu erstellen, der immer mit der Transaktion übereinstimmt.

Ich wollte dies morgen abschließen, damit ich eine vollständige Auszahlungs- / Einzahlungsfunktion für Binance habe. Vorausgesetzt, es wird akzeptiert, würde ich dies vorantreiben und das erste halbe Dutzend Austausch durchführen.

@kroitor was brauchst du, um diesen Code in das Haupt-Repository zu bekommen? Es ist umständlich für mich, mehrere Branches zu schreiben, ohne sie zusammen zu verwenden, was bedeutet, dass ich die Branches in meinem Fork zusammenführen muss. Gibt es einen besseren Weg?

@kroitor was brauchst du, um diesen Code in das Haupt-Repository zu bekommen?

@grandmore im Grunde, machen Sie einfach einen Pull-Request und von dort aus sollten wir es schnell lösen können ... wir brauchen nur eine js-Datei des Austauschs) thx)

@kroitor Lassen Sie mich den Code fertigstellen und ich werde es morgen tun. Es sind eigentlich 2 Dateien, da Exchange.js die gemeinsamen parseTransactions() enthalten muss

parseTransactions (transactions, side = undefined, market = undefined, since = undefined, limit = undefined) {
  let result = Object.values (transactions || []).map (transaction => this.parseTransaction (transaction, side))
  result = sortBy (result, 'timestamp')
  let symbol = (typeof market !== 'undefined') ? market['symbol'] : undefined
  return this.filterBySymbolSinceLimit (result, symbol, since, limit)
} 

@kroitor @grandmore Ich schreibe Cobinhood-Code für Transaktionen. Was halten Sie von möglichen Werten für den Rückgabestatus von Transaktionen?

parseTransactionStatus (status) {
        if (status in ['tx_pending_two_factor_auth', 'tx_pending_email_auth', 'tx_pending_approval']) {
            return 'pending_user_action';
        } else if (status === 'tx_approved') {
            return 'approved';
        } else if (status in ['tx_processing', 'tx_pending', 'tx_sent']) {
            return 'pending';
        } else if (status in ['tx_timeout', 'tx_invalid', 'tx_cancelled', 'tx_rejected']) {
            return 'canceled';
        } else if (status in ['tx_confirmed']) {
            return 'ok';
        } else {
            'unkown';
        }
    }

@ifern Jede Börse hat unterschiedliche Antworten, sodass wir sie entweder standardisieren können oder einen Mittelweg finden. Ich mag Ihren Ansatz der Bündelung, im Wesentlichen die gleichen Fehler in einem Antworttyp ['tx_timeout', 'tx_invalid', 'tx_cancelled', 'tx_rejected'] = cancelled.

Das habe ich für Binance getan.

parseTransactionStatus (status, side) {
  if (!(side === 'deposit' || side === 'withdraw'))
    throw new ExchangeError (this.id + 'deposit/withdraw side set incorrectly: ' + side);
  if (side === 'deposit') {
    let statuses = {
        '0': 'pending',
        '1': 'complete',
    };
    return (status in statuses) ? statuses[status] : status.toLowerCase ();
  } else {
    let statuses = {
        '0': 'email sent',
        '1': 'cancelled',
        '2': 'awaiting approval',
        '3': 'rejected',
        '4': 'processing',
        '5': 'failure',
        '6': 'complete',
    };
    return (status in statuses) ? statuses[status] : status.toLowerCase ();
  }
}

Vielleicht wäre es in Ordnung, "abgelehnt" und "nicht bestanden" von "abgesagt" zu unterscheiden. Außerdem möchte ich "ausstehend" unterscheiden, wenn die Börse die Anfrage verarbeitet, und "ausstehend", wenn die Börse auf zusätzliche Schritte vom Benutzer wartet. Aber ich weiß nicht, ob dieser zusätzliche Zustand für andere wirklich nützlich wäre.

type TransactionStates = (
  'ok' |
  'cancelled' |
  'pending' |
  'approved' |
  'rejected' |
  'failure' |
  'pending-user-action');

Was halten Sie von möglichen Werten für den Rückgabestatus von Transaktionen?

Ich würde mit so wenig unterschiedlichen Status wie möglich gehen, nämlich:

  • ok (Einzahlung gutgeschrieben oder finanziert/erhalten oder Abhebung wurde gesendet, wurde zum Senden genehmigt usw.)
  • pending (Einzahlung ausstehend/Bestätigung oder Auszahlung wartet auf Bestätigung oder Genehmigung)
  • error (aus welchem ​​Grund auch immer, von welcher Partei abgelehnt oder gescheitert)
  • canceled (die meisten Benutzer werden es wahrscheinlich wollen, viele Börsen werden jedoch keine abgebrochenen historischen Transaktionen melden)

Für mich scheinen die obigen Codes auf das abgestimmt zu sein, was wir im Durchschnitt von den APIs der Börsen erhalten würden... Der Rest der Status - nicht so sicher... Immer noch offen für Diskussionen und Argumente.

@kroitor Ich habe eine synthetische ID erstellt, damit Transaktionen auch dann identifiziert werden können, wenn die Börse keine ID

const syntheticId = this.hash (timestamp.toString () + currency.id + side + amount + address);

Die ID wird so berechnet, dass sie bei der Neuberechnung immer dieselbe ID zurückgibt. Aber ich habe 2 Fragen.

  1. Die Hash-ID muss identisch sein, wenn sie aus einer der unterstützten Sprachen erstellt wird. Ich verwende den Standard this.hash() Ich kodiere nicht in Python, daher wollte ich mit Ihnen prüfen, ob dies in Python funktioniert.

  2. Ich kann entweder die synthetische ID anstelle der ID zurückgeben oder eine Null-ID zurückgeben und beispielsweise eine Hash-ID hinzufügen. Was würdest du bevorzugen?

Dies

let result = {
  ...
  'id': null, 
  'hashid': syntheticId,
  ...
};

oder dieses

let result = {
  ...
  'id': syntheticId, 
  ...
};

Wie organisiere ich einen Pull-Request?

Ich kann entweder die synthetische ID anstelle der ID zurückgeben oder eine Null-ID zurückgeben und beispielsweise eine Hash-ID hinzufügen. Was würdest du bevorzugen?

Ich würde es vorziehen, die ID undefined wenn sie von der Börse nicht bekannt ist, und die Hash-ID in Ihrem Benutzerland außerhalb der Bibliothek zu behalten, da die Hash-ID Ihre benutzerspezifische Aufgabe ist. Nicht alle Benutzer brauchen die übermäßigen Anrufe. Mit anderen Worten, ich würde normalisierte Daten bevorzugen, wobei normalisiert bedeutet, dass die Daten nicht dupliziert werden sollten, und wenn ein Feld immer aus denselben Daten rekonstruiert wird, würde ich es vorziehen, es nicht zu denormalisieren (keine weiteren Felder oder Sonderfälle hinzuzufügen).

Wie organisiere ich einen Pull-Request?

Allgemein: https://help.github.com/articles/creating-a-pull-request/

Sie forken das Repo an Ihren Github. Nehmen Sie dann die Änderungen vor. Dann gibt es eine Schaltfläche, um einen Pull-Request aus diesen Änderungen an das ursprüngliche Repository zu erstellen.

Bezüglich ccxt: https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how -to-contribute-code

Lassen Sie es uns wissen, wenn Sie weitere Fragen haben. Danke!

Haben Sie fees Objekt fees Objekt über mehrere Klassen hinweg vom gleichen Typ wäre, sodass die Währung in fees selbst wenn sie mit der Auszahlung identisch wäre.

@clarkmoody unsere Standardgebührenstruktur (Sie finden sie unter Bestellungen und Trades) in der gesamten Bibliothek ist:

fee: {
    'cost': 123.45,
    'rate': 0.001,
    'currency': 'ETH',
}

)

unsere Standard-Gebührenstruktur

Groß! Ich habe mich nur gewundert, da die Beispieldatenstruktur früher in diesem Thread nicht alle diese Felder hatte.

@kroitor Ich habe eine Pull-Anfrage für die Binance-Einzahlungs- und Auszahlungscodes erstellt. (https://github.com/ccxt/ccxt/pull/2526)

@grandmore thx! Ich werde es bald zusammen mit diesem zusammenführen: https://github.com/ccxt/ccxt/pull/2355 by @lfern )

@kroitor Irgendwelche Neuigkeiten zu dieser PR werden hinzugefügt? Vielen Dank.

@grandmore tut

@kroitor Ich möchte die Auszahlungsgebühren zu Binance hinzufügen, aber sie werden berechnet und nicht direkt von der API zurückgegeben.
ich kann hinzufügen

const withdrawFee = await this.wapiGetWithdrawFee(this.extend(para, params));

Was gibt withdrawFee: 0.0005

Ich möchte die 'withdrawFee' zu den globalen Daten des Objekts hinzufügen, damit in der 'parseTransaction()-Schleife' darauf verwiesen werden kann. Sie haben diese Struktur oben, aber sie sagt, dass sie veraltet ist. Wo kann ich das speichern?

'fees': {
    'trading': {
    'tierBased': false,
    'percentage': true,
    'taker': 0.001,
    'maker': 0.001,
},
// should be deleted, these are outdated and inaccurate
'funding': {...

Kann ich das einfach so hinzufügen?

'fees': {
    'trading': {
    'tierBased': false,
    'percentage': true,
    'taker': 0.001,
    'maker': 0.001,
    'withdrawFee': 0.0005
},
// should be deleted, these are outdated and inaccurate
'funding': {...
...

Ich muss nur nachsehen, bevor ich etwas schreibe.

@kroitor Ich

Gibt es hierzu Neuigkeiten? :)

@kroitor In Bezug auf Ihren obigen Vorschlag denke ich, dass price nicht in der Transaktionsdatenstruktur enthalten sein sollte.

Gibt es einen zwingenden Grund, es zu behalten?

@clarkmoody Sie haben Recht, es ist ein Artefakt aus dem Kopieren der Handelsstruktur, der Preis gehört nicht dorthin.

Ich weiß, dass ich etwas zu spät zu dieser Party bin, aber ich würde vorschlagen, fetchTransfers anstelle von "Transaktionen" für die einheitliche private API zu verwenden, da _transactions_ jede Bewegung (Handel, Einzahlung, Auszahlung usw.) kommuniziert. Natürlich bilden die Ein- und Auszahlungen und Überweisungen möglicherweise diese Arbeiten, obwohl viele Börsen, mit denen ich zusammengearbeitet habe, sie zu einem einzigen Endpunkt kombiniert halten.

@mrasband thx, werde das auch berücksichtigen.

@kroitor gibt es dazu ein Update? Sie haben im April "Wird bald mit der Zusammenführung beginnen )" geschrieben. Wir sind im August und es gibt mehrere PRs, die Abhebungs- und Einzahlungsmethoden implementieren, die ebenfalls darauf warten, zusammengeführt zu werden. Ist noch etwas unklar/zu definieren? Oder was blockiert diese PRs?

@firepol Entschuldigung, das ist völlig meine Schuld, anfangs wollten wir mehr Informationen über andere Börsen sammeln, um noch mehr Vereinheitlichung zu

@kroitor du bist ein fantastisches Beispiel für einen Projektbetreuer 👌, danke für die harte Arbeit (sorry, dass diese Nachricht alle im Thread spammt - aber ich wollte auf jeden Fall _Danke_ sagen).

Okay, ich habe gdax, gemini und cobinhood zusammengeführt. Binance ist auf dem Weg. Dem Handbuch wurden einige Klarstellungen hinzugefügt, es ist jedoch immer noch unvollständig. Ihre Hilfe beim Hinzufügen der restlichen Methoden und Dokumente wird sehr geschätzt!

Wichtige Hinweise:

  • Feld side Feld type
  • mögliche Werte für das Feld type : 'deposit' oder 'withdrawal' (nicht withdraw , sondern withdrawal !)
  • address Feld zur Transaktionsstruktur hinzugefügt (bezeichnet den Sender oder den Empfänger der Transaktion, je nach Typ)
  • mögliche Werte für einen Status sind: 'ok' (bestätigt und dem Saldo gutgeschrieben), 'pending' (unbestätigt oder noch nicht gutgeschrieben), 'failed' , 'canceled'

Ich würde dieses Thema vorerst schließen, aber bitte zögern Sie nicht, hier oder anderswo weiter zu posten, wenn Sie Probleme oder Schwierigkeiten mit dem oben genannten haben. Ich werde mit dem Polieren der Implementierungen und dem Hinzufügen von Bugfixes, falls erforderlich, fortfahren. Vielen Dank!

Hallo @kroitor ,

Seitenfeld in Typenfeld umbenannt

In Python ist type der Name eines eingebauten, daher denke ich, dass es eine gute Idee ist, diesen Namen nicht zu verwenden, der das eingebaute überschreibt, und bei side bleiben. Dies sollte kein Problem sein, wenn Sie es in einem Json verwenden, da es die aktuelle Verwendung zu sein scheint, aber es kann verwirrend sein, da alle Methoden "side" verwenden und im Json nicht side, sondern type. Auch sind die Leute an die Nebenterminologie gewöhnt, um Kauf/Verkauf zu identifizieren, warum also nicht die gleiche Terminologie auch für Einzahlungen/Auszahlungen beibehalten? Vielleicht wollten Sie die beiden Konzepte Kaufen/Verkaufen und Einzahlung/Auszahlung trennen und somit ein anderes Feld verwenden... aber ich denke, es ist nicht wirklich notwendig... Gedanken?

Warum also nicht die gleiche Terminologie auch für Einzahlungen/Auszahlungen beibehalten?

weil du es selbst gesagt hast:

Menschen sind an die Nebenterminologie gewöhnt, um Kauf/Verkauf zu identifizieren,

) Mit anderen Worten, wenn side überall entweder buy oder sell ist, möchten wir nicht wirklich eine dritte und eine vierte mögliche Seite zur Liste der möglichen Werte hinzufügen für dieses Feld. Dies wird meiner Meinung nach zu Verwirrung führen. Daher type .

PS Natürlich wird das Feld type selbst auch bei Bestellungen verwendet ( limit , market ), daher ist es auch nicht der beste Name für die Finanzierungsrichtung. Wir dachten auch darüber nach, es direction , aber wir landeten vorerst bei type da wir denken, dass es semantisch dem entsprechen würde, womit die Börsen selbst antworten.

@kroitor- Frage für die Börsen, die keine unterschiedlichen Methoden zum Abrufen von Abhebungen und Einzahlungen haben, wie zum Beispiel:

  • bitstamp (kann den gesamten Verlauf abrufen, einschließlich der Trades)
  • bitfinex (Einzahlungen + Auszahlungen)
  • ...

Ist es fetchTransactions so einzustellen?

  • 'fetchTransactions': wahr,
  • 'fetchWithdrawals': falsch,
  • 'fetchDeposits': falsch,

Ich sehe, dass fetchTransactions für diese Börsen implementiert ist:

  • exmo
  • gdax
  • Zwillinge
  • bitstamp ist fälschlicherweise als fetchMyTrades implementiert und Issue #3749 behebt dieses Problem bereits

Ich schlage vor, einen neuen Parameter in der Methode hinzuzufügen, für type .

  • undefined : alle Arten von Transaktionen (Einzahlungen, Auszahlungen, Trades)
  • withdrawal : nur Auszahlungen zurückgeben
  • deposit : nur Einzahlungen zurückgeben

Bei bitfinex würden Sie diese Methode beispielsweise ohne Angabe des Typs aufrufen und alle Ein- und Auszahlungen erhalten. Oder ruf es 2 mal an. Zuerst mit type = 'deposit' , dann mit type = 'withdrawal' .

Auf bitstamp würden Sie diese Methode ohne Angabe des Typs aufrufen und Sie erhalten alle Ein- und Auszahlungen (wie bei bitfinex). Da erwartet wird, dass Trades in dieser Methodenantwort nicht zurückgegeben werden, sollten sie gefiltert werden.
Oder nennen Sie es 2 mal, wie bei bitfinex: Zuerst mit type = 'deposit' , dann mit type = 'withdrawal' .
Um mytrades zu erhalten, sollte stattdessen die Methode fetchMyTrades aufgerufen werden, und fetchMyTrades sollte die Transaktionen (Auszahlung und Einzahlung) herausfiltern, die in diesem Methodenaufruf nicht erwartet werden.

Was denken Sie?

Ich würde mich freuen, in diesem Bereich beizutragen, da ich eine Buchhaltungssoftware schreibe, die Börsenhistorien abrufen muss.

Ich kann mit Bitstamp beginnen, da es einfach sein sollte, die Art der Transaktion ohne Probleme zu bestimmen (siehe Diskussion in PR #3736)

Soll fetchTransactions so eingestellt werden?

  • 'fetchTransactions': wahr,
  • 'fetchWithdrawals': falsch,
  • 'fetchDeposits': falsch,

Ja)

Ich schlage vor, einen neuen Parameter in der Methode für den Typ hinzuzufügen.

Ich denke nicht, dass wir das wirklich tun sollten. Ich würde vorschlagen, dass wir besser außerhalb der Bibliothek (im Userland) filtern. Um es zu erklären, denken Sie so: Wenn es keine nativen fetchDeposits und fetchWithdrawals und nur fetchTransactions verfügbar ist, bedeutet dies, dass die betreffende Börse alle gemischt ausgibt , ohne Filter. Andernfalls, wenn die Börse es erlaubt, sie zu filtern, wäre native fetchDeposits oder fetchWithdrawals wahr, und dann würde der Benutzer erst die entsprechende Methode aufrufen.

In Fällen, in denen wir nur fetchTransactions lädt CCXT zuerst die gesamte Antwort (die gemischte Transaktionen enthält) herunter. Dann muss die Bibliothek jede der heruntergeladenen Transaktionen analysieren, um ihre tatsächlichen vereinheitlichten Typen herauszufinden. Beachten Sie, dass wir trotzdem alle Ein- und Auszahlungen analysieren werden. An diesem Punkt haben wir alle Übertragungen geparst, also warum sollte eine Bibliothek sie filtern, nachdem wir den schwierigsten Teil der Arbeit bereits erledigt haben? Klingt nach einer künstlichen (unnötigen) Einschränkung der Ergebnisse, obwohl wir eigentlich alle behandelt haben. Wir geben lieber alle geparsten Ergebnisse zurück und lassen den Benutzer entscheiden. Darüber hinaus bieten wir eine Reihe nützlicher Methoden an, und die meisten Sprachen bieten Syntax-Zucker für Filter und Maps, wie zum Beispiel:

// JavaScript

// native js syntax filters
transactions = await exchange.fetchTransactions ()
deposits = transactions.filter (t => t.type === 'deposit')
withdrawals = transactions.filter (t => t.type === 'withdrawal')

// alternatively, filter with ccxt
grouped = exchange.groupBy (transactions, 'type')
console.log (grouped['deposit'])
console.log (grouped['withdrawal'])
# Python

# native python syntax filters
transactions = exchange.fetch_transactions ()
deposits = [t for t in transactions if t['type'] == 'deposit']
withdrawals = [t for t in transactions if t['type'] == 'withdrawal']

# alternatively, filter with ccxt
grouped = exchange.group_by(transactions, 'type')
print(grouped['deposit'])
print(grouped['withdrawal'])
// PHP

// native php syntax filters
$transactions = $exchange->fetch_transactions ();
$deposits = array_filter ($transactions, function ($t) { return ($t['type'] === 'deposit'; });
$withdrawals = array_filter ($transactions, function ($t) { return ($t['type'] === 'withdrawal'; });

// alternatively, filter with ccxt
$grouped = $exchange->group_by($transactions, 'type');
echo print_r($grouped['deposit'], true) . "\n";
echo print_r($grouped['withdrawal'], true) . "\n";

Wie Sie von oben sehen können, macht es also sehr wenig Sinn, den Filter in der Bibliothek zu haben – stellen Sie sich vor, jede Bibliothek würde all diese Filter in ihrem Quellcode duplizieren und das Rad immer wieder neu erfinden ... Das ist nicht das, was wir wirklich in Bezug auf die Bibliotheksgestaltung wünschen. Die Idee dahinter ist: Wenn es mit muttersprachlicher Syntax auf sehr kurzem Weg oder mit einer einzeiligen Klausel leicht machbar ist – dann gehört es nicht zur Bibliothekscodebasis . Dies erklärt hoffentlich, warum wir keinen Filter für fetchTransactions hinzufügen würden. Wir hätten nur fetchTransactions ohne Typ und das war's.

Auf der anderen Seite könnten Sie fetchTransactions mit has['fetchDeposits'] = 'emulated' , wie im Handbuch zu Exchange- has Eigenschaften beschrieben: https://github.com/ccxt/ccxt/wiki /Manual#exchange -Eigenschaften und mit einer zusätzlichen Basis
Wrapper, der fetchDeposits → fetchTransactions+filter und fetchWithdrawals → fetchTransactions+filter aufrufen würde.

Anstatt also fetchTransactions mit einem angegebenen type aufzurufen, würden Sie lieber emulierte Versionen von fetchDeposits oder fetchWithdrawals Wrappern aufrufen. Aufgrund der Paginierung kann dies jedoch wirklich schwierig werden (um limit und since mit gefilterten Ergebnissen Respekt zu zollen). Am Ende würden wir uns also nicht die Mühe machen, etwas nachzuahmen, das von der fraglichen Börse nicht sehr gut unterstützt wird (den Aufwand lohnt sich unserer Meinung nach nicht).

Ich würde mich freuen, in diesem Bereich beizutragen, da ich eine Buchhaltungssoftware schreibe, die Börsenhistorien abrufen muss.
Ich kann mit Bitstamp beginnen, da es einfach sein sollte, die Art der Transaktion ohne Probleme zu bestimmen (siehe Diskussion in PR #3736)

Ihre Hilfe bei der Lösung des Bitstamp-Problems ist weiterhin sehr willkommen! Eigentlich ist jede Hilfe immer noch willkommen. Wenn das oben Genannte für Sie keinen Sinn ergibt und Sie versuchen möchten, diesen Aspekt auf elegantere Weise zu vereinen, würden wir ihn gerne überprüfen und zusammenführen. Lassen Sie es mich wissen, wenn Sie weitere Fragen haben. Vielen Dank!

Danke @kroitor für deine nette Antwort und die Hinweise auf das Handbuch, wow diese Bibliothek ist wirklich komplex, gut dokumentiert und es gibt immer etwas Neues zu lernen.

Es macht absolut Sinn, dass Ihre Erklärung, Dinge nicht zu filtern und das im Userland sein zu lassen.

Der Bitstempel- Fall ist dann ein bisschen knifflig. Denn in #3749 hat der Benutzer nicht erwartet, dass Ein- und Auszahlungen in fetchMyTrades und ich stimme ihm zu.

Als Benutzer von CCXT würde ich versuchen, die Methoden zu verwenden, ohne den Code und jede Austauschdokumentation zu überprüfen. Ich erwarte, dass die Bibliothek einfach zu bedienen ist und mir so viele Informationen wie möglich zur Verfügung stellt, damit ich nicht die offizielle Dokumentation der Austausch-API lesen muss.

Das heißt, wenn eine Methode nicht das zurückgibt, was der Methodenname sagt, sollte die Methode dokumentiert werden, damit der Benutzer weiß, was sie nicht tut, wenn er sie von seiner IDE aus überschreibt oder anklickt.

Ich sehe 2 Lösungen für Bitstamp.

1) Implementieren Sie fetchTransactions und im Grunde ist es dasselbe wie fetchMyTrades.
2) Befreien Sie sich von fetchMyTrades und verwenden Sie nur fetchTransactions.

Ich würde Lösung Nr. 2 vorschlagen, da der zu verwendende Bitstamp-Endpunkt transactions heißt.

Wenn es viele Börsen gibt, die bitstamp mögen und nur einen Endpunkt haben, um alle Transaktionen abzurufen, könnte vielleicht eine neue "vereinheitlichte" Methode namens fetchAllTransactions , die fetchMyTrades rechtfertigt: false, zB für bitstamp wäre es:

'fetchMyTrades': false,
'fetchTransactions': false,
'fetchWithdrawals': false,
'fetchDeposits': false,
'fetchAllTransactions': true,

So würde man alles falsch sehen, aber fetchAllTransactions ist wahr, das heißt, das ist ein Endpunkt wie der Bitstamp-Endpunkt, der alles auf einmal holt.

Auf diese Weise wäre auch für den Benutzer, der #3749 hinterlegt hat, klar, dass er eine der grouped oder Filtermethoden in der nativen Programmiersprache verwenden und aus der riesigen Liste mit allem herausfiltern sollte, was er braucht.

Was denken Sie?

Update : Der Nachteil von Lösung 2 ist, dass es für alle Leute kaputt geht, die sich auf fetchMyTrades verlassen. Aber Sie können ihnen sagen, dass sie immer überprüfen sollten, ob eine Funktion verfügbar ist, wenn nicht die nächste usw. Wenn ich die Überprüfung einer Reihe von Einzahlungshistorien von Börsen automatisieren müsste, würde ich in meinem Benutzerland eine Hilfsfunktion implementieren, um genau das zu überprüfen.

Was denken Sie?

Ich würde einen Kompromiss vorschlagen – wir könnten uns für Lösung 1 entscheiden, wobei sowohl fetchMyTrades als auch fetchTransactions (beide im Grunde auf dieselbe gemeinsame Methode abgebildet) beibehalten werden, und wir würden type: undefined/None/null , type:'limit' , type: 'market' , type:'withdrawal' , type:' 'deposit' sowohl von fetchMyTrades als auch von fetchTransactions, wo/wenn möglich. Und ich würde eine Ausnahmewarnung hinzufügen, die diesen Code selbstdokumentiert machen würde, etwa:

async fetchMyTrades (...) {
    return await this.fetchMyTradesAndTransactions (type, ...); // type might not be needed
}

async fetchTransactions (...) {
    return await this.fetchMyTradesAndTransactions (type, ...); // type might not be needed
}

async fetchMyTradesAndTransactions (type, ...) {
    if (this.options['fetchMyTradesAndTransactionsWarning']) {
        const warning = this.id + " " +
            "fetchMyTrades / fetchTransactions will return all trades and transactions " +
            "mixed in the same array. Make sure you add proper handling and set this.options['fetchMyTradesAndTransactionsWarning'] = false " +
            "or add { 'options': { 'fetchMyTradesAndTransactionsWarning': false }} to exchange constructor " +
            "to acknowledge this message and turn off this warning.";
        throw new ExchangeError (warning);
    }
    ...
    // parsing overrides to handle them both
    return ...;
}

Der Benutzer kann es einfach nicht überspringen und wir erzwingen auf diese Weise das Bewusstsein für das oben genannte börsenspezifische Verhalten. Wie klingt das für dich?

Ich mag die Ausnahme, es ist eine ziemlich clevere Möglichkeit, einen Benutzer auf die ungewöhnliche Situation aufmerksam zu machen, ohne ihn dazu zu zwingen, die offiziellen Börsendokumente zu überprüfen, und eine Option bereitzustellen, um die Warnung loszuwerden.

Dies wäre also der außergewöhnliche Austausch, der die Transaktionen nach Typ filtert/gruppiert? Oder was meinst du mit:

    // parsing overrides to handle them both
    return ...;

? Sie wollen parseTrades und dann auch parseTransactions aufrufen?

Ich habe einen ersten Entwurf des Bitstamp-Refactorings erstellt.

Ich habe deine Absicht mit type nicht genau verstanden, aber ich habe es so verwendet:

Typ: Transaktionen oder Trades.

Wenn ich die allgemeine Methode aufrufe von:

fetchMyTrades Ich setze type = 'myTrades'
fetchTransactions Ich setze type = 'transactions'

dann:

...
response = call the API
if (type === 'myTrades') {
    result = filter to get only trades
    return parseOrders(result)
} else {
    result = filter to get only trades
    return parseTransactions(result)
}

So hätten wir auch einen Bool verwenden können, zB fetchTransactions true|false.

So muss ich nur noch die Methode parseTransaction implementieren und die Antwort richtig filtern. Bitte korrigieren Sie mich, wenn Sie etwas anderes beabsichtigt haben, ich werde wahrscheinlich nach 20:30 Uhr MEZ daran arbeiten, also keine Eile mit der Antwort ;)

Ich habe Ihre Absicht mit Typ nicht genau verstanden, aber ich habe sie so verwendet:

Ok, meine Absicht war wahrscheinlich nicht klar, lassen Sie uns dies ein wenig klarstellen ) Laut ihren Dokumenten gibt der Endpunkt user_transactions alle Ledger-Zeilen zurück, einschließlich Trades, Finanzierungstransaktionen (Ein- und Auszahlungen) und interne Überweisungen.

bitstamp-transactions

Zurück zu unserer einheitlichen API haben wir fetchMyTrades (gibt ein Array von Wörterbüchern zurück) und wir haben auch fetchTransactions (gibt auch ein Array von Wörterbüchern zurück, und die Methode fehlt möglicherweise oder wird durch die zwei andere separate Methoden – fetchDeposits und fetchWithdrawals , wenn die Vermittlungsstelle es nicht zulässt, sie in einem Aufruf abzurufen).

Jede einheitliche Handelsstruktur hat ein type ( limit oder market ):
https://github.com/ccxt/ccxt/wiki/Manual#trade -Struktur

Jede einheitliche Transaktionsstruktur hat auch ein type ( deposit oder withdraw ):
https://github.com/ccxt/ccxt/wiki/Manual#transaction -structure

Da sowohl fetchMyTrades als auch fetchTransactions Arrays von Wörterbüchern zurückgeben und da alle Wörterbücher ein type der Benutzer dieses type , um zu filtern und zu unterscheiden Geschäfte aus Transaktionen (sei es Einzahlungen oder Abhebungen).

Wenn wir etwas weiter darüber nachdenken, denke ich, sollten wir Folgendes tun:

Standardmäßig würde fetchMyTrades nur die Trades zurückgeben (Zeilen, die keine Transaktionen oder interne Überweisungen sind, geparst mit parseTrade ), und fetchTransactions würde nur die Transaktionen (Zeilen, die sind keine Trades oder internen Transfers, geparst mit parseTransaction ). Dies steht im Einklang mit dem Design unserer einheitlichen API. Und das ist, was ein Benutzer von der Beschreibung im Handbuch erwarten würde.

Ich würde auch eine freundliche Warnung in jeder der beiden Methoden aufbewahren, um sicherzustellen, dass der Benutzer sich der möglichen Paginierungsprobleme bewusst ist. Der Benutzer, der alle Transaktionen haben möchte, würde die implizite Methode einfach direkt aufrufen. Für mich fühlt sich das im Moment wie eine saubere Herangehensweise an Bitstamp an. Und du?

Wir könnten auch einige Flags zu fetchMyTrades / fetchTransactions hinzufügen, um differenzierte Ergebnisse zurückzugeben, mit gemischten Zeilen, die entweder von diesem oder jenem Parser geparst werden, aber ich würde diesen Aspekt nicht wirklich emulieren (versuchen, die Lücken im Austausch zu füllen). ' apis mit emulierten Methoden erweist sich sowohl in Bezug auf die Architektur als auch auf die Benutzererfahrung oft als schlechte Entscheidung).

Sieht gut aus, ich setze genau so um.

Übrigens, ich habe versucht, die Methode filter verwenden, wie Sie vorgeschlagen haben, aber sie wird in Python nicht richtig transpiliert.

        if (type === 'myTrades') {
            let result = response.filter (t => t['type'] === '2');
            return this.parseTrades (result, market, since, limit);
        } else {
            let result = response.filter (t => t['type'] === '0' || t['type'] === '1');
            return this.parseTransactions (result, market, since, limit);
        }

Transpiliert nicht ... Ich bekomme immer noch response.filter (mit der Pfeilfunktion) in Python ... was natürlich nicht funktioniert. Abhilfe dafür? Oder ist das ein Transpiler-Bug?

Abhilfe dafür?

let result = this.filterBy (result, 'type', '2'); // this will transpile properly

Um es noch einmal zusammenzufassen, wir können .filter () innerhalb der lib nicht wirklich verwenden, da der Transpiler immer noch ziemlich dumm ist und nicht weiß, wie man Code-Introspektion macht, die er tun muss, um Closures und Mappings zu erkennen und sie zu konvertieren richtiges Verständnis für Python-Listen (dies beinhaltet komplexe Ausdrücke mit Variablen außerhalb des Ausdrucksbereichs, was die Transpilierung erschwert). Daher haben wir eine Reihe von Helfern: .filterBy , .groupBy , .indexBy , .sortBy und so weiter. Wenn Sie in Quelldateien nach dem Wort "filter" suchen, werden Sie unzählige Beispiele dafür finden, wie es in anderen Börsen zum Filtern von Ergebnisarrays nach Schlüsselwert verwendet wird. Hoffe das hilft) Lass es mich wissen, wenn nicht) Thx! )

Ich finde viele Beispiele für filterBy, aber keine Beispiele zum Filtern nach mehr als einem Wert. In unserem Fall filterBy 2 ok, um myTrades zu erhalten.

Aber um Einzahlungen (0) UND Auszahlungen (1) zu erhalten, muss ich nach 0 und 1 filtern. Gibt es so eine Methode? Wenn nicht, kannst du vielleicht einen erstellen? Ansonsten kann ich versuchen, selbst eine zu machen, sollte eine einfache Schleife sein.

UPDATE: oder vielleicht um das Leben nicht komplizierter zu machen: Ich filtere zuerst nach 0, dann nach 1, dann kombiniere ich die 2 Arrays zu einem. Haben wir eine Hilfsmethode, die korrekt transpiliert, um 2 Arrays zu kombinieren?

Haben wir eine Hilfsmethode, die korrekt transpiliert, um 2 Arrays zu kombinieren?

// ...
let groups = this.groupBy (results, 'type');
let transactions = this.arrayConcat (groups['0'], groups['1']); // 0 (deposits) + 1 (withdrawals)
transactions = this.sortBy (transactions, 'timestamp');
let trades = this.sortBy (groups['2'], 'timestamp');
// ...

Die tatsächlichen Feldnamen und Schlüsselwerte hängen davon ab, ob Sie mit noch nicht geparsten Ergebnissen des Austauschs oder mit bereits geparsten/vereinheitlichen Ergebnissen arbeiten.

@firepol Entschuldigung, ich habe vergessen, dass ich die Methode .filterByArray früher erstellt habe, also ja, Sie können das in nur einer Zeile tun )

screen shot 2018-09-08 at 00 33 34

Ähm ... eigentlich ist das obige Beispiel ein schlechtes Beispiel dafür, wie man filterByArray nicht verwendet, da es eine Multipass-Traversion des Arrays durchführt, während in diesem speziellen Fall mit der auf dem Screenshot in meiner vorherigen Nachricht gezeigten bibox alles getan werden kann in nur einem Durchgang:

    parseTickers (rawTickers, symbols = undefined) {
        let tickers = [];
        for (let i = 0; i < rawTickers.length; i++) {
            tickers.push (this.parseTicker (rawTickers[i]));
        }
        return this.filterByArray (tickers, 'symbol', symbols);
    }

    parseTickers (rawTickers, symbols = undefined) {
        let tickers = [];
        for (let i = 0; i < rawTickers.length; i++) {
            let ticker = this.parseTicker (rawTickers[i]);
            if ((typeof symbols !== 'undefined') || (this.inArray (ticker['symbol'], symbols))) {
                tickers.push (ticker);
            }
        }
        return tickers;
    }

Aber wie auch immer, Sie haben ein komplettes Set an Tools und können diese nach Belieben kombinieren.

[RANT] Habe ich dir gesagt, dass ich die Bitstamp-API irgendwie hasse? Bisher sind es die schlechtesten, die ich nach lykke und cex gesehen und verwendet habe, Nr. 3 in den Top 3 der hässlichsten Krypto-APIs, die bisher gesehen wurden ... [/RANT]

Ich gebe für heute Abend auf, ich habe meine WIP-Implementierung hierher verschoben:

https://github.com/firepol/ccxt/tree/bitstamp-fetch-transactions

Ich werde in einer Sekunde einen Fehler im Zusammenhang mit dem saugfähigen Bitstempel melden.

UPDATE: eigentlich kann ich parseTransactions überschreiben, anstatt einen Fehler einzureichen. Wenn Sie neugierig sind, kann das Problem (in meinem Zweig habe ich gerade meinen oben verlinkten Fork eingeschoben) wie folgt (in Python) reproduziert werden:

bitstamp = ccxt.bitstamp('...')
test1 = bitstamp.fetch_transactions('BTC') # this won't work, not a valid market apparently
test2 = bitstamp.fetch_transactions('BTC/USD')

In test2 wird BTC/USD zu btcusd, was keine gültige Währung ist, daher schlägt es in den exchange.parse_transactions mit diesem Fehler fehl:

  File "/home/paul/projects-python/ccxt/python/ccxt/base/exchange.py", line 1293, in parse_transactions
    code = currency['code'] if currency else None
KeyError: 'code'

@firepol Wir verwenden normalerweise einen der folgenden Geschmacksrichtungen:

let symbol = 'BTC/USD';
let market = this.market (symbol); // market['id'] == 'btcusd'
let base = market['base']; // BTC, also baseId = btc
let quote = market['quote']; // USD, also quoteId = usd

Dies hilft in Situationen, in denen Sie einen Währungscode in ein Marktsymbol und zurück umwandeln müssen.

Ich habe ein kleines Problem, der Fehler tritt in der Methode exchange.fetch_transactions auf. Wenn ich es in bitstamp.js kopiere, um es zu überschreiben, erhalte ich einen weiteren Syntaxfehler, da der Transpiler die erste Zeile nicht korrekt transpiliert:

  File "/home/paul/projects-python/ccxt/python/ccxt/bitstamp.py", line 456
    result = Object.values(transactions or []).map(transaction => self.parse_transaction(transaction, currency))
                                                                ^
SyntaxError: invalid syntax

Tut mir leid, Sie mit so vielen Fragen zu belästigen, aber bitstamp ist wirklich eine Qual, und der Transpiler ist auch ziemlich hart... Können Sie helfen?

@firepol sicher! Das Problem ist, dass wir die folgenden Regeln nicht brechen können: https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#derived -exchange-classes, insbesondere diese:

Entfalten Sie alle Karten und Verständnisse zu grundlegenden for-Schleifen

Wie ich bereits sagte, können wir keine Syntax transpilieren, die Closures beinhaltet – das ist alles Syntax mit js .filter und js .map , daher ersetzen wir alle .filter/.map/.forEach entweder durch einen Aufruf zu einer Basismethode oder einer einfachen for-Schleife. Siehe dieses Beispiel:

Sie müssen sich jedoch nicht wirklich darum kümmern, da ich es sowieso beim Zusammenführen bearbeiten und bereinigen werde. Lass es mich wissen, wenn du mehr hast)

Voila, fertig. Ich kann eine interessante Entdeckung hinzufügen, die ich gerade gemacht habe: Siehe die API-Dokumente: https://www.bitstamp.net/api/

USER TRANSACTIONS-Endpunkt: https://www.bitstamp.net/api/v2/user_transactions/ {currency_pair}/

Sie denken vielleicht, dass Sie nur Einzahlungen (Typ 0) oder Auszahlungen (Typ 1) erhalten können, aber das ist nicht möglich. Um sie zu bekommen, musst du alles holen. Ich meine die Historie aller Trades für alle Währungen (alle Paare/Märkte). Deshalb habe ich so umgesetzt, wie ich es gemacht habe. Ich musste lange kämpfen, um alles herauszufinden. Jetzt ist es getestet und funktioniert.

@firepol Nachdem

JFYI Wir denken, dass das Hinzufügen der tag die mit den address für bestimmte Währungen und Transaktionen verbunden sind, eine vernünftige Sache ist, um sie mit der Rendite von createDepositAddress/fetchDepositAddress Einklang zu bringen, deshalb haben wir damit begonnen Hinzufügen von tag zu parseTransaction wo fehlten und wir haben auch die Beschreibung einer Transaktionsstruktur im Handbuch aktualisiert.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

jjhesk picture jjhesk  ·  3Kommentare

nashse picture nashse  ·  3Kommentare

jjhesk picture jjhesk  ·  3Kommentare

shnhrrsn picture shnhrrsn  ·  3Kommentare

gaardiolor picture gaardiolor  ·  3Kommentare