[PYTHON] Les débutants créeront un bot de trading automatique Bitcoin visant beaucoup d'argent! Partie 4 [sans serveur]

サーバレスアーキテクチャ.png Cette fois précédente, j'ai créé un "trading automatique de bitcoin de type Bot" Nous avons utilisé Lambda d'AWS pour créer une ** configuration sans serveur ** populaire! C'est dans le cloud, donc il continue de fonctionner de manière semi-permanente même si mon PC s'arrête. C'est juste un Bot!

À propos de la configuration du cloud J'ai choisi le sans serveur parce que j'ai entendu dire que les frais d'utilisation sont ** très bon marché ** + ** faciles à gérer **. [Référence]

Picture67.png

En regardant le service que j'ai réellement utilisé cette fois, ... Avec la configuration suivante ** 1 $ par mois !! ** Presentation4.png

Estimation

Service cible Prix estimé
Lambda $0
DynamoDB $0
cloudwatch $1.00?

Lambda · Lambda offre gratuitement 1 000 000 requêtes et 400 000 Go-secondes de temps de calcul par mois. [Référence]

▶ Une fois par minute, si vous l'exécutez pendant un mois, 1 x 60m x 24h x 31 jours = 44640 fois, donc ** marge **

DynamoDB · L'offre gratuite d'AWS comprend 25 Go de stockage Amazon DynamoDB et traite jusqu'à 200 millions de demandes. [Référence]

** 200 millions ... (゜ Д ゜) ** Peut-il être dépassé par les individus? (Il semble que cela dépende de la capacité d'écriture et de lecture par heure, Je m'en fiche car je ne l'utiliserai pas si dur cette fois. )

cloudwatch : 1,00 $ [[Reference]] pour 1 million d'événements personnalisés créés (https://aws.amazon.com/jp/cloudwatch/pricing/)

▶ Si vous l'exécutez une fois par minute pendant un mois, 1 x 60 mx 24h x 31 jours = 44 640 fois, donc 1,00 $?

▶ Après l'avoir déplacé pendant environ une semaine, il n'y a aucun signe qu'il augmentera du tout ... Si vous restez debout pendant un mois et qu'il est de 0 yen, il sera fixé à 0 yen.

spécification

Le mouvement est comme d'habitude ** Achetez quand ça devient moins cher et vendez quand ça coûte cher! Cela reste un bot stupide comme **. Je veux résoudre ce problème rapidement, mais je ne peux pas trouver un bon algorithme. .. .. ..

① Obtenez le montant de la transaction précédente du DB (ce montant est la base du jugement) ② Annuler si la transaction précédente demeure ② Si vous avez Bitcoin et que le prix augmente, vendez-le! (Et enregistrez le montant de la transaction dans DB) ③ Si vous avez du yen japonais et que le prix baisse, achetez-le! (Et enregistrez le montant de la transaction dans DB)

la mise en oeuvre

Implémentez les trois dans AWS du diagramme d'architecture ci-dessus. (Cela fonctionne simplement en définissant ces trois!) aaaaa.PNG

  1. DynamoDB --Créer un tableau
  2. Lambda --Codage --Déployer dans l'environnement d'exécution de code
  3. CloudWach --Définissez le Lambda défini ci-dessus dans le planificateur

1.DynamoDB Picture1.png

Lambda, l'environnement d'exécution de code utilisé cette fois, ne peut pas enregistrer les valeurs par exécution séquentielle, donc Utilisez la base de données.

Créez les deux tableaux suivants.

① last_transaction_price --Enregistrez le prix de la transaction ② séquence-Enregistrez le nombre de transactions réussies

** ① last_transaction_price --Enregistrez le prix de la transaction **

①-1. Créez le tableau suivant à partir de [Create Table]

・ Nom de la table: last_transaction_pric ・ Clé primaire: trade_number (type numérique)

①-2. Enregistrer l'enregistrement à partir de [Créer un élément](enregistrer manuellement uniquement le premier) キャプチャ3.PNG

** ② séquence-Enregistrez le nombre de transactions réussies **

①-1. Créez le tableau suivant à partir de [Create Table]

・ Nom de la table: séquence ・ Clé primaire: nom (chaîne de caractères)

①-2. Enregistrer l'enregistrement à partir de [Créer un élément](enregistrer manuellement uniquement le premier) キャプチャ4.PNG

2.Lambda Picture2.png

① Codage ② Création de rôles ③ Créer Lambda ④ Déployer ⑤ Test

** ① Codage **

Constitution Cette fois, il augmente de diverses manières. []···dossier

[zaif]  |- main.py | - [Config] - * zaif_keys.json * -Stocke les clés et les secrets zaif | - [Aws] - * dynamodb_utils.py * -Une classe qui facilite l'utilisation de l'API DynamoDB d'aws. | - [Define] - * common_define.py * - (Principalement utilisé dans DynamoDB) Une classe qui définit et résume les chaînes de caractères | - [Exception] - * error.py * -Classes qui résument les erreurs uniques | -... - [Partie 1](http://qiita.com/speedkingg/items/2d874beee26106ce9f9a#2api installation)

■main.py

main.py


# -*- coding: utf-8 -*-
import json
from zaifapi import ZaifPublicApi  #Classe qui exécute une API qui ne nécessite pas d'informations d'authentification publiées par Zaif
from zaifapi import ZaifPrivateApi  #Une classe qui exécute une API qui nécessite des informations d'identification publiées par Zaif
from pprint import pprint  #Pour l'affichage(Il affiche json proprement)
from aws.dynamodb_utils import DynamoDBUtils  #Classes qui utilisent Dynamodb
from define.common_define import CommonDefine  #Une classe qui définit des constantes telles que les noms de table
from exception.error import *  #Une classe qui définit une erreur propriétaire

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)


#Ici est exécuté lorsqu'il est appelé de Lamda
def lambda_handler(event, context):
    try:
        #Obtenez des informations actuelles
        info = _get_info()
        last_price = info["last_price"]
        funds_btc = info["funds_btc"]
        funds_jpy = info["funds_jpy"]
        open_orders = info["open_orders"]

        #Acquisition du montant de la transaction précédente
        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))

        #Annuler si la transaction est en attente
        if order_id > 0 and open_orders > 0:
            try:
                print('■ Annulé.')
                pprint(zaif_private.cancel_order(order_id=order_id))
            except Exception as e:
                print(e)
            else:
                #Supprimer le montant de la transaction précédente
                _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)

        #Quand tu as du btc et que le prix monte
        if funds_btc != 0 and last_price > last_transaction_price:
            _sell_btc(last_price, funds_btc)

        #Quand vous avez jpy et que le prix baisse
        #(Unité minimum (0).0001btc minutes) lorsque vous avez plus que le yen japonais)
        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


#Acquisition du montant de la transaction précédente
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('■ Ce sont les informations actuelles.')
    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('■ J'ai demandé la vente de Bitcoin.')
        pprint(trade_result)
        if trade_result["order_id"] == 0:
            _put_last_transaction_price(last_price, 0)
            print('■ La transaction est terminée.')
        elif trade_result["order_id"] != 0:
            _put_last_transaction_price(last_price, trade_result["order_id"])
            print('■ La transaction est en attente.')

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


def _buy_btc(last_price, funds_jpy):
    try:
        #Étant donné que l'API prend en charge jusqu'à 4 chiffres après la virgule décimale, arrondissez()
        amount = round(float(funds_jpy) / last_price, 4)
        print('▼[trace]_buy_btc')
        print('amount: ' + str(amount))
        #Acheter Bitcoin
        trade_result = zaif_private.trade(currency_pair="btc_jpy", action="bid",
                                          price=last_price, amount=amount)
        print('■ J'ai demandé l'achat de Bitcoin')
        pprint(trade_result)
        if trade_result["order_id"] == 0:
            _put_last_transaction_price(last_price, 0)
            print('■ La transaction est terminée.')
        elif trade_result["order_id"] != 0:
            _put_last_transaction_price(last_price, trade_result["order_id"])
            print('■ La transaction est en attente.')

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


#Écrire les informations de transaction dans la base de données
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


#Supprimer les informations de transaction précédentes
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.jsonLes débutants créeront un bot de trading automatique Bitcoin visant beaucoup d'argent! Partie 3

■[aws] - dynamodb_utils.py -Les méthodes de base pour faire fonctionner DynamoDB sont résumées. ・ Il est utilisé en citant * main.py *.

dynamodb_utils.py


# coding:utf-8

import boto3
from exception.error import *  #Une classe qui définit une erreur propriétaire


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

    #Obtenez tous les enregistrements dans la table spécifiée (jusqu'à 1 Mo)
    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 reçu en spécifiant la table(item)En tant qu'enregistrement ou écrasement
    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

    #Obtenir l'enregistrement en spécifiant la table et la clé primaire
    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

    #Obtenir un enregistrement en spécifiant la table et la clé primaire / clé de tri
    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

    #Mettre à jour l'enregistrement en spécifiant la table, la clé primaire et l'élément de mise à jour
    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

    #Supprimer l'enregistrement en spécifiant la table et la clé primaire
    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 -C'est une classe qui définit et résume les chaînes de caractères utilisées principalement dans DynamoDB. -Gérer tous ensemble afin que vous puissiez en profiter lorsque vous souhaitez changer le nom de la colonne, etc. plus tard.

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 -Un groupe de classes qui résume les erreurs uniques. -Utiliser lorsque le nom d'erreur que vous souhaitez émettre n'est pas préparé en standard.

error.py


# -*- coding: utf-8 -*-
class ResourceNotFoundError(Exception):
    #Exception lorsque les données à acquérir n'existent pas

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

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


class IllegalArgumentError(Exception):
    #Exception si l'argument saisi n'est pas valide

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

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

** ② Création de rôle **

-Créez un rôle avec les privilèges nécessaires pour exécuter Lambda. キャプチャ33.PNG

  1. IAM ▶ Rôle ▶ Sélectionnez «Créer un nouveau rôle»
  2. Sélection du type de rôle: AWS Lambda
  3. Attacher la politique: AmazonDynamoDBFullAccess, AWSLambdaFullAccess
  4. Entrez le nom du rôle et cliquez sur "Créer un rôle"

** ③ Créé par Lambda **

-Créer un Lambda qui exécute réellement le code. キャプチャaaaaa.PNG

  1. Lambda ▶ Fonction ▶ Sélectionnez «Créer une fonction Lambda»
  2. Cliquez sur l'onglet "Paramètres des fonctions" sur la gauche
  3. Entrez un nom (tout va bien) Runtime : sélectionnez python2.7 Rôle existant : sélectionnez le rôle créé dans " ② Créer un rôle **" Paramètres détaillés ▶ Délai d'expiration: augmentez la valeur à 10 secondes
  4. "Suivant" ▶ "Créer"

** ④ Déployer **

・ ** ③ Mettez le code sur le Lambda créé dans ** Create Lambda **.

  1. Ouvrez l'onglet "Paramètres" et modifiez le gestionnaire en ** main.lambda_handler ** (Ce qui signifie appeler et exécuter main.py) キャプチャaws.PNG
  2. ** ① Codage ** pour compresser le groupe de codes créé *** Attention à ne pas devenir [zaif] - [zaif] -main.py! (Correct: [zaif] -main.py) **
  3. Sélectionnez l'onglet Code et téléchargez le fichier Capture qya.PNG

** ⑤ Test **

Appuyez sur le bouton "Enregistrer et tester", et si ** Résultat de l'exécution: Succès **, c'est OK! aaaaキャプチャ.PNG

3.CloudWach Picture3.png -Définissez le Lambda créé ci-dessus pour qu'il soit exécuté périodiquement. キャプチ.PNG

  1. CloudWatch ▶ Règles ▶ Création de règles
  2. "Planifier" ▶ Changer la valeur à 1 "Ajouter une cible" ▶ Fonction *: ** Fonction Lambda créée ci-dessus ** Capture.PNG
  3. «Paramètres détaillés» ▶ Saisir le nom * ▶ «Paramètres de règle»

en conclusion

Cette fois, la procédure était longue. .. .. Je vous remercie pour votre travail acharné! Avec ce paramètre, vous avez un Bot ** qui échange BitCoin de manière semi-permanente! Maintenant, pensez à la logique rentable! !! (๑ • ̀ ㅂ • ́) و✧ Je vais faire des essais et des erreurs ٩ (• ౪ • ٩)

Citation

Générateur de logo d'amis Kemono

▶ Il y a des gens dans le monde qui font des choses merveilleuses. Merci de l'utiliser. Merci beaucoup.

Historique des corrections

・ 2017/4/27: J'ai oublié d'écrire le plus important ** main.py **. .. .. Je suis désolé. ・ 2017/4/27: Correction d'erreur de notation MarkDown (alt Merci de nous avoir signalé.)

Recommended Posts

Les débutants créeront un bot de trading automatique Bitcoin visant beaucoup d'argent! Partie 4 [sans serveur]
Les débutants créeront un bot de trading automatique Bitcoin visant beaucoup d'argent! Partie 3 [Bot local]
Les débutants créeront un bot de trading automatique Bitcoin visant beaucoup d'argent! Partie 1 [Acquisition d'informations]
Les débutants créeront un bot de trading automatique Bitcoin visant beaucoup d'argent! Partie 2 [Transaction avec API]
Créer un bot pour Skype sur EC2 (CentOS)
[Phase de réflexion] Prédire la hauteur d'arrêt, stratégie visant beaucoup d'argent-concept-edit