[PYTHON] Anfänger machen einen automatischen Bitcoin-Handelsbot, der viel Geld anstrebt! Teil 4 [Serverlos]

サーバレスアーキテクチャ.png Diesmal vorher habe ich "Bitcoin Automatic Trading Bot-like" gemacht. Wir haben Lambda von AWS verwendet, um eine beliebte ** serverlose Konfiguration ** zu erstellen! Es befindet sich in der Cloud und läuft daher auch dann semipermanent weiter, wenn mein PC stoppt. Es ist nur ein Bot!

Informationen zur Cloud-Konfiguration Ich habe mich für Serverless entschieden, weil ich gehört habe, dass die Nutzungsgebühr ** sehr günstig ** + ** einfach zu verwalten ** ist. [Referenz]

Picture67.png

Mit Blick auf den Service, den ich dieses Mal tatsächlich genutzt habe, ... Mit der folgenden Konfiguration ** 1 $ pro Monat !! ** Presentation4.png

Schätzen

Zieldienst Schätzpreis
Lambda $0
DynamoDB $0
cloudwatch $1.00?

Lambda · Lambda bietet 1.000.000 kostenlose Anfragen und 400.000 GB-Sekunden Rechenzeit pro Monat kostenlos an. [Referenz]

▶ Einmal pro Minute, wenn Sie es einen Monat lang ausführen, 1 x 60 m x 24 h x 31 Tage = 44.640 Mal, also ** Marge **

DynamoDB · AWS Free Tier umfasst 25 GB Amazon DynamoDB-Speicher und verarbeitet bis zu 200 Millionen Anfragen. [Referenz]

** 200 Millionen ... (゜ Д ゜) ** Kann es von Einzelpersonen überschritten werden? (Es scheint, dass es von der Schreib- und Lesekapazität pro Stunde abhängt, Es ist mir egal, weil ich es diesmal nicht so hart benutzen werde. )

cloudwatch : 1,00 USD [[Referenz]] für 1 Million erstellte benutzerdefinierte Ereignisse (https://aws.amazon.com/jp/cloudwatch/pricing/)

▶ Wenn Sie es einen Monat lang einmal pro Minute ausführen, 1 x 60 m x 24 h x 31 Tage = 44.640 Mal, also 1,00 USD?

▶ Nach etwa einer Woche Umzug gibt es keine Anzeichen dafür, dass es überhaupt zunimmt ... Wenn Sie einen Monat stehen und es 0 Yen ist, wird es auf 0 Yen festgelegt.

Spezifikation

Die Bewegung ist wie gewohnt ** Kaufen, wenn es billiger wird, und verkaufen, wenn es teuer wird! Es bleibt ein dummer Bot wie **. Ich möchte das Problem schnell beheben, kann mir aber keinen guten Algorithmus ausdenken. .. .. ..

① Holen Sie sich den vorherigen Transaktionsbetrag aus der DB (dieser Betrag ist die Grundlage für die Beurteilung) ② Abbrechen, wenn die vorherige Transaktion bestehen bleibt ② Wenn Sie Bitcoin haben und der Preis steigt, verkaufen Sie es! (Und speichern Sie den Transaktionsbetrag in DB) ③ Wenn Sie japanischen Yen haben und der Preis fällt, kaufen Sie ihn! (Und speichern Sie den Transaktionsbetrag in DB)

Implementierung

Implementieren Sie die drei in AWS des obigen Architekturdiagramms. (Es funktioniert nur durch Einstellen dieser drei!) aaaaa.PNG

  1. DynamoDB
  • Tabelle erstellen
  1. Lambda --Coding
  • In Code-Ausführungsumgebung bereitstellen
  1. CloudWach --Stellen Sie das oben eingestellte Lambda im Scheduler ein

1.DynamoDB Picture1.png

Lambda, die diesmal verwendete Codeausführungsumgebung, kann daher keine Werte durch sequentielle Ausführung speichern Verwenden Sie die Datenbank.

Erstellen Sie die folgenden zwei Tabellen.

① last_transaction_price - Zeichnet den Transaktionspreis auf ② Sequenz - Notieren Sie die Anzahl der erfolgreichen Transaktionen

** ① last_transaction_price - Den Transaktionspreis aufzeichnen **

①-1. Erstellen Sie die folgende Tabelle aus [Tabelle erstellen]

・ Tabellenname: last_transaction_pric ・ Primärschlüssel: Handelsnummer (numerischer Typ)

①-2. Aufzeichnung der Registrierung unter [Element erstellen](nur die erste manuell registrieren) キャプチャ3.PNG

** ② Sequenz-Notiere die Anzahl der erfolgreichen Transaktionen **

①-1. Erstellen Sie die folgende Tabelle aus [Tabelle erstellen]

・ Tabellenname: Reihenfolge ・ Primärschlüssel: Name (Zeichenfolge)

①-2. Aufzeichnung der Registrierung unter [Element erstellen](nur die erste manuell registrieren) キャプチャ4.PNG

2.Lambda Picture2.png

① Codierung ② Rollenerstellung ③ Lambda erstellen ④ Bereitstellen ⑤ Test

** ① Codierung **

Verfassung Dieses Mal nimmt es auf verschiedene Weise zu. []···Ordner

[zaif]  |- main.py | - [Config] - * zaif_keys.json * - Speichert zaif-Schlüssel und Geheimnisse | - [Aws] - * dynamodb_utils.py * - Eine Klasse, die die Verwendung der DynamoDB-API von aws vereinfacht. | - [Definieren] - * common_define.py * - (Wird hauptsächlich in DynamoDB verwendet) Eine Klasse, die Zeichenfolgen definiert und zusammenfasst | - [Ausnahme] - * error.py * -Klassen, die eindeutige Fehler zusammenfassen | -... - [Teil 1](http://qiita.com/speedkingg/items/2d874beee26106ce9f9a#2api Installation)

■main.py

main.py


# -*- coding: utf-8 -*-
import json
from zaifapi import ZaifPublicApi  #Klasse, die eine API ausführt, für die keine von Zaif veröffentlichten Authentifizierungsinformationen erforderlich sind
from zaifapi import ZaifPrivateApi  #Eine Klasse, die eine API ausführt, für die von Zaif veröffentlichte Anmeldeinformationen erforderlich sind
from pprint import pprint  #Zur Ausstellung(Es zeigt json ordentlich an)
from aws.dynamodb_utils import DynamoDBUtils  #Klassen, die Dynamodb betreiben
from define.common_define import CommonDefine  #Eine Klasse, die Konstanten wie Tabellennamen definiert
from exception.error import *  #Eine Klasse, die einen proprietären Fehler definiert

dynamodb = DynamoDBUtils()

zaif_keys_json = open('config/zaif_keys.json', 'r')
zaif_keys = json.load(zaif_keys_json)

KEY = zaif_keys["key"]
SECRET = zaif_keys["secret"]

zaif_public = ZaifPublicApi()
zaif_private = ZaifPrivateApi(KEY, SECRET)


#Hier wird ausgeführt, wenn von Lamda aufgerufen
def lambda_handler(event, context):
    try:
        #Aktuelle Informationen abrufen
        info = _get_info()
        last_price = info["last_price"]
        funds_btc = info["funds_btc"]
        funds_jpy = info["funds_jpy"]
        open_orders = info["open_orders"]

        #Erwerb des vorherigen Transaktionsbetrags
        trade_count = _get_trade_count()
        last_transaction_data = _get_last_transaction_data(trade_count)
        last_transaction_price = last_transaction_data[CommonDefine.LAST_TRANSACTION_PRICE]
        order_id = last_transaction_data[CommonDefine.ORDER_ID]

        print('▼[info] last_transaction_price: ' + str(last_transaction_price) + ', order_id: ' + str(order_id))

        #Abbrechen, wenn die Transaktion angehalten wird
        if order_id > 0 and open_orders > 0:
            try:
                print('■ Abgebrochen.')
                pprint(zaif_private.cancel_order(order_id=order_id))
            except Exception as e:
                print(e)
            else:
                #Löschen Sie den vorherigen Transaktionsbetrag
                _delete_last_transaction_price(trade_count)
        elif open_orders == 0:
            dynamodb.update_by_partition_key(CommonDefine.LAST_TRANSACTION_TABLE,
                                             CommonDefine.TRADE_NUMBER, trade_count,
                                             CommonDefine.ORDER_ID, 0)

        #Wenn Sie BTC haben und der Preis steigt
        if funds_btc != 0 and last_price > last_transaction_price:
            _sell_btc(last_price, funds_btc)

        #Wenn Sie jpy haben und der Preis fällt
        #(Mindesteinheit (0).0001btc Minuten) wenn Sie mehr als japanische Yen haben)
        elif funds_jpy > last_transaction_price / 10000 and last_price < last_transaction_price:
            _buy_btc(last_price, funds_jpy)

    except ResourceNotFoundError:
        raise
    except IllegalArgumentError:
        raise
    except Exception:
        raise


#Erwerb des vorherigen Transaktionsbetrags
def _get_last_transaction_data(trade_count):
    try:
        last_transaction_data = dynamodb.get_item_by_partition_key(CommonDefine.LAST_TRANSACTION_TABLE,
                                                                   CommonDefine.TRADE_NUMBER, trade_count)

        if "Item" not in last_transaction_data:
            raise ResourceNotFoundError("last_transaction_data is not found.")

        if CommonDefine.LAST_TRANSACTION_PRICE not in last_transaction_data["Item"]:
            raise ResourceNotFoundError(CommonDefine.LAST_TRANSACTION_PRICE + " is not found.")

        if CommonDefine.ORDER_ID not in last_transaction_data["Item"]:
            raise ResourceNotFoundError(CommonDefine.ORDER_ID + " is not found.")

    except ResourceNotFoundError:
        raise
    except IllegalArgumentError:
        raise
    except Exception:
        raise

    return last_transaction_data["Item"]


def _get_trade_count():
    trade_count_data = dynamodb.get_item_by_partition_key(CommonDefine.SEQUENCE,
                                                          CommonDefine.SEQUENCE_NAME, CommonDefine.TRADE_COUNT)
    if "Item" not in trade_count_data:
        raise ResourceNotFoundError("trade_count_data is not found.")

    if CommonDefine.COUNT_NUMBER not in trade_count_data["Item"]:
        raise ResourceNotFoundError(CommonDefine.COUNT_NUMBER + " is not found.")

    return trade_count_data["Item"].get(CommonDefine.COUNT_NUMBER)


def _get_info():
    info = {}

    info["last_price"] = int(zaif_public.last_price('btc_jpy')["last_price"])

    trade_info = zaif_private.get_info2()
    info["funds_btc"] = trade_info["funds"]["btc"]
    info["funds_jpy"] = trade_info["funds"]["jpy"]
    info["open_orders"] = trade_info["open_orders"]

    print('■ Dies sind die aktuellen Informationen.')
    print('last_price: ' + str(info["last_price"]))
    print('funds_btc: ' + str(info["funds_btc"]))
    print('funds_jpy: ' + str(info["funds_jpy"]))
    print('open_orders: ' + str(info["open_orders"]))

    return info


def _sell_btc(last_price, funds_btc):
    try:
        trade_result = zaif_private.trade(currency_pair="btc_jpy", action="ask",
                                          price=last_price, amount=funds_btc)
        print('■ Ich habe den Verkauf von Bitcoin beantragt.')
        pprint(trade_result)
        if trade_result["order_id"] == 0:
            _put_last_transaction_price(last_price, 0)
            print('■ Die Transaktion ist abgeschlossen.')
        elif trade_result["order_id"] != 0:
            _put_last_transaction_price(last_price, trade_result["order_id"])
            print('■ Die Transaktion wird gehalten.')

    except ResourceNotFoundError:
        raise
    except IllegalArgumentError:
        raise
    except Exception:
        raise


def _buy_btc(last_price, funds_jpy):
    try:
        #Da die API bis zu 4 Nachkommastellen unterstützt, runden Sie()
        amount = round(float(funds_jpy) / last_price, 4)
        print('▼[trace]_buy_btc')
        print('amount: ' + str(amount))
        #Bitcoin kaufen
        trade_result = zaif_private.trade(currency_pair="btc_jpy", action="bid",
                                          price=last_price, amount=amount)
        print('■ Ich habe den Kauf von Bitcoin beantragt')
        pprint(trade_result)
        if trade_result["order_id"] == 0:
            _put_last_transaction_price(last_price, 0)
            print('■ Die Transaktion ist abgeschlossen.')
        elif trade_result["order_id"] != 0:
            _put_last_transaction_price(last_price, trade_result["order_id"])
            print('■ Die Transaktion wird gehalten.')

    except ResourceNotFoundError:
        raise
    except IllegalArgumentError:
        raise
    except Exception:
        raise


#Schreiben Sie Transaktionsinformationen in die DB
def _put_last_transaction_price(last_transaction_price, order_id):
    try:
        trade_count = _get_trade_count()

        trade_count += 1
        put_record_value = {
            CommonDefine.TRADE_NUMBER: trade_count,
            CommonDefine.LAST_TRANSACTION_PRICE: last_transaction_price,
            CommonDefine.ORDER_ID: order_id
        }
        dynamodb.put_item(CommonDefine.LAST_TRANSACTION_TABLE, put_record_value)

        dynamodb.update_by_partition_key(CommonDefine.SEQUENCE,
                                         CommonDefine.SEQUENCE_NAME, CommonDefine.TRADE_COUNT,
                                         CommonDefine.COUNT_NUMBER, trade_count)
    except ResourceNotFoundError:
        raise
    except IllegalArgumentError:
        raise
    except Exception:
        raise


#Löschen Sie die vorherigen Transaktionsinformationen
def _delete_last_transaction_price(trade_count):
    try:
        trade_count -= 1
        dynamodb.delete_by_partition_key(CommonDefine.LAST_TRANSACTION_TABLE,
                                         CommonDefine.TRADE_NUMBER, CommonDefine.SEQUENCE_NAME)

        dynamodb.update_by_partition_key(CommonDefine.SEQUENCE,
                                         CommonDefine.SEQUENCE_NAME, CommonDefine.TRADE_COUNT,
                                         CommonDefine.COUNT_NUMBER, trade_count)
    except ResourceNotFoundError:
        raise
    except IllegalArgumentError:
        raise
    except Exception:
        raise

■[config] - zaif_keys.jsonAnfänger machen einen automatischen Bitcoin-Handelsbot, der viel Geld anstrebt! Teil 3

■[aws] - dynamodb_utils.py -Die grundlegenden Methoden zum Betrieb von DynamoDB sind zusammengefasst. ・ Es wird durch Zitieren aus * main.py * verwendet.

dynamodb_utils.py


# coding:utf-8

import boto3
from exception.error import *  #Eine Klasse, die einen proprietären Fehler definiert


class DynamoDBUtils:
    def __init__(self):
        self.dynamodb = boto3.resource('dynamodb')

    #Holen Sie sich alle Datensätze in der angegebenen Tabelle (bis zu 1 MB)
    def scan(self, table_name):
        if isinstance(table_name, str) is False or isinstance(table_name, unicode):
            raise IllegalArgumentError('item is not str/unicode')

        table = self.dynamodb.Table(table_name)
        response = table.scan()

        print('▼[trace][DynamoDB access]scan')
        print('table_name: ' + table_name)
        print('response:')
        print(str(response))

        return response

    #Json erhielt durch Angabe der Tabelle(item)Als Aufzeichnung oder Überschreiben
    def put_item(self, table_name, item):
        if isinstance(table_name, str) is False or isinstance(table_name, unicode):
            raise IllegalArgumentError('item is not str/unicode')
        if isinstance(item, dict) is False:
            raise IllegalArgumentError('item is not dict')

        table = self.dynamodb.Table(table_name)
        response = table.put_item(
            Item=item
        )

        print('▼[trace][DynamoDB access]put_item')
        print('table_name: ' + table_name)
        print('put_item: ' + str(item))
        print('response:')
        print(str(response))

        return response

    #Erhalten Sie einen Datensatz, indem Sie Tabelle und Primärschlüssel angeben
    def get_item_by_partition_key(self, table_name, partition_key, partition_key_value):
        if isinstance(table_name, str) is False or isinstance(table_name, unicode):
            raise IllegalArgumentError('item is not str/unicode')

        table = self.dynamodb.Table(table_name)
        response = table.get_item(
            Key={partition_key: partition_key_value}
        )

        print('▼[trace][DynamoDB access]get_item_by_partition_key')
        print('table_name: ' + table_name)
        print('partition_key: ' + str(partition_key) + ', partition_key_value: ' + str(partition_key_value))
        print('response:')
        print(str(response))

        return response

    #Holen Sie sich den Datensatz, indem Sie die Tabelle und den Primärschlüssel / Sortierschlüssel angeben
    def get_item_by_partition_key_and_sort_key(self, table_name, partition_key, partition_key_value,
                                               sort_key, sort_key_value):
        if isinstance(table_name, str) is False or isinstance(table_name, unicode):
            raise IllegalArgumentError('item is not str/unicode')

        table = self.dynamodb.Table(table_name)
        response = table.get_item(
            Key={partition_key: partition_key_value,
                 sort_key: sort_key_value}
        )

        print('▼[trace][DynamoDB access]get_item_by_partition_key_and_sort_key')
        print('table_name: ' + table_name)
        print('partition_key: ' + str(partition_key) + ', partition_key_value: ' + str(partition_key_value))
        print('sort_key: ' + str(sort_key) + ', sort_key_value: ' + str(sort_key_value))
        print('response:')
        print(str(response))

        return response

    #Aktualisieren Sie den Datensatz, indem Sie Tabelle, Primärschlüssel und Aktualisierungselement angeben
    def update_by_partition_key(self, table_name, partition_key, partition_key_value, update_key, update_value):
        if isinstance(table_name, str) is False or isinstance(table_name, unicode):
            raise IllegalArgumentError('item is not str/unicode')

        table = self.dynamodb.Table(table_name)
        response = table.update_item(
            Key={
                partition_key: partition_key_value
            },
            UpdateExpression='SET ' + update_key + ' = :uk',
            ExpressionAttributeValues={
                ':uk': update_value
            }
        )

        print('▼[trace][DynamoDB access]update_by_partition_key')
        print('table_name: ' + table_name)
        print('partition_key: ' + str(partition_key) + ', partition_key_value: ' + str(partition_key_value))
        print('update_key: ' + str(update_key) + ', update_value: ' + str(update_value))
        print('response:')
        print(str(response))

        return response

    #Löschen Sie den Datensatz, indem Sie die Tabelle und den Primärschlüssel angeben
    def delete_by_partition_key(self, table_name, partition_key, partition_key_value):
        if isinstance(table_name, str) is False or isinstance(table_name, unicode):
            raise IllegalArgumentError('item is not str/unicode')

        table = self.dynamodb.Table(table_name)
        response = table.delete_item(
            Key={partition_key: partition_key_value}
        )

        print('▼[trace][DynamoDB access]delete_by_partition_key')
        print('table_name: ' + table_name)
        print('partition_key: ' + str(partition_key) + ', partition_key_value: ' + str(partition_key_value))
        print('response:')
        print(str(response))

        return response

■[define] - common_define.py -Es ist eine Klasse, die die hauptsächlich in DynamoDB verwendeten Zeichenfolgen definiert und zusammenfasst.

common_define.py


# -*- coding: utf-8 -*-
class CommonDefine:
    def __init__(self):
        pass

    # dynamoDB table name
    LAST_TRANSACTION_TABLE = "last_transaction_price"
    SEQUENCE = "sequence"

    # dynamoDB key name
    TRADE_NUMBER = "trade_number"
    LAST_TRANSACTION_PRICE = "last_transaction_price"
    SEQUENCE_NAME = "name"
    COUNT_NUMBER = "count_number"
    ORDER_ID = "order_id"

    # other
    TRADE_COUNT = "trade_count"

■[exception] - error.py

error.py


# -*- coding: utf-8 -*-
class ResourceNotFoundError(Exception):
    #Ausnahme, wenn die zu erfassenden Daten nicht vorhanden sind

    def __init__(self, message):
        self.message = message

    def __str__(self):
        return "Requested resource " + self.message + " not found."


class IllegalArgumentError(Exception):
    #Ausnahme, wenn das eingegebene Argument ungültig ist

    def __init__(self, message):
        self.message = message

    def __str__(self):
        return "Illegal argument (" + self.message + ")"

** ② Rollenerstellung **

  1. IAM ▶ Rolle ▶ Wählen Sie "Neue Rolle erstellen".
  2. Auswahl des Rollentyps: AWS Lambda
  3. Richtlinie anhängen: AmazonDynamoDBFullAccess, AWSLambdaFullAccess
  4. Geben Sie den Rollennamen ein und klicken Sie auf "Rolle erstellen".

** ③ Erstellt von Lambda **

  1. Lambda ▶ Funktion ▶ Wählen Sie "Lambda-Funktion erstellen"
  2. Klicken Sie links auf die Registerkarte "Funktionseinstellungen"
  3. Geben Sie einen Namen ein (alles ist in Ordnung) Laufzeit : Wählen Sie python2.7 Vorhandene Rolle : Wählen Sie die unter " ** Rolle erstellen **" erstellte Rolle aus. Detaillierte Einstellungen ▶ Zeitüberschreitung: Erhöhen Sie den Wert auf 10 Sekunden
  4. "Weiter" ▶ "Erstellen"

** ④ Bereitstellen **

・ ** ③ Geben Sie den Code in das in ** Create Lambda ** erstellte Lambda ein.

  1. Öffnen Sie die Registerkarte "Einstellungen" und ändern Sie den Handler in ** main.lambda_handler ** (Bedeutet, main.py aufzurufen und auszuführen) キャプチャaws.PNG
  2. ** ① Codierung ** zum Komprimieren der erstellten Codegruppe *** Pass auf, dass du nicht [zaif] - [zaif] -main.py wirst! (Richtig: [zaif] -main.py) **
  3. Wählen Sie die Registerkarte Code und laden Sie die Datei hoch Capture qya.PNG

** ⑤ Test **

Klicken Sie auf die Schaltfläche "Speichern und testen". Wenn ** Ausführungsergebnis: Erfolgreich **, ist dies in Ordnung! aaaaキャプチャ.PNG

3.CloudWach Picture3.png

  1. CloudWatch ▶ Regeln ▶ Regeln erstellen
  2. "Zeitplan" ▶ Ändern Sie den Wert auf 1 "Ziel hinzufügen" ▶ Funktion *: ** Lambda-Funktion oben erstellt ** Capture.PNG
  3. "Detaillierte Einstellungen" ▶ Name eingeben * ▶ "Regeleinstellungen"

abschließend

Diesmal war das Verfahren lang. .. .. Danke für deine harte Arbeit! Mit dieser Einstellung haben Sie einen Bot **, der BitCoin semi-permanent handelt! Denken Sie jetzt nur an die profitable Logik! !! (๑ • ̀ ㅂ • ́) و✧ Ich werde Versuch und Irrtum machen ٩ (• ౪ • ٩)

Zitat

Kemono Friends Logo Generator

▶ Es gibt Menschen auf der Welt, die wunderbare Dinge machen. Vielen Dank für die Verwendung. Vielen Dank.

Korrekturgeschichte

・ 27.04.2017: Ich habe vergessen, das wichtigste ** main.py ** zu schreiben. .. .. Es tut mir Leid. ・ 27.04.2017: MarkDown-Notationsfehlerkorrektur (alt Vielen Dank für den Hinweis.)

Recommended Posts

Anfänger machen einen automatischen Bitcoin-Handelsbot, der viel Geld anstrebt! Teil 4 [Serverlos]
Anfänger machen einen automatischen Bitcoin-Handelsbot, der viel Geld anstrebt! Teil 3 [Lokaler Bot]
Anfänger machen einen automatischen Bitcoin-Handelsbot, der viel Geld anstrebt! Teil 1 [Informationsbeschaffung]
Anfänger machen einen automatischen Bitcoin-Handelsbot, der viel Geld anstrebt! Teil 2 [Transaktion mit API]
Erstellen Sie einen Bot für Skype unter EC2 (CentOS)
[Denkphase] Vorhersage der Stopphöhe, Strategie, die auf viel Geld-Konzept-Bearbeitung abzielt