【AWS】bitbank 新規注文

1. 使用するサービス

(AWS)

  • Lambda
  • IAM
  • SSM

 
(外部サービス)

  • bitbank API 


2. 概要

bitbank Apiを使用して、自作の注文サイトを作成します。
基本的な仕組みはbitflyer Lightning Apiで実装したものと同じでURLを叩くのが最終的なゴールです。
buffalokusojima.hatenablog.com


3. 実装

今回はバックエンド側を実装します。フロントは特にbitflyerと違いはなく、渡すパラメータが異なるのみなので省略します。

大まかな違いとしては、ヘッダの中身とパラメータくらいです。

const ssm = new (require('aws-sdk/clients/ssm'))();
const request = require('request');
const crypto = require('crypto');

exports.handler = function(event, context, callback) {
    
    var apikey;
    var sercretKey;
    
    var body = JSON.parse(event.body);
    
    if(!body){
        console.log("body empty");
          callback(null, {
              statusCode: 400,
              body: JSON.stringify({message: "body empty"}),
              headers: {"Content-type": "application/json"}
            });
        return;
    }
    
    const COIN_PAIR = body.coin_pair;
    
    const PRICE = body.price;
    
    const SIDE = body.side;
    
    const SIZE = body.size;
    
    const TYPE = body.type;
    
    const PARAMETERS = body.parameters;

    const ORDER_METHOD = body.order_method;
    
    if(!TYPE && !PARAMETERS){
        console.log("invalid order:",body);
          callback(null, {
              statusCode: 400,
              body: JSON.stringify({message: "invalid order"}),
              headers: {"Content-type": "application/json"}
            });
        return;
    }
    
    if(COIN_PAIR != 'xrp_jpy'){
        console.log("invalid coin pair");
          callback(null, {
              statusCode: 400,
              body: JSON.stringify({message: "invalid order"}),
              headers: {"Content-type": "application/json"}
            });
        return;
    }
    
    if(!checkElement(body)){
            console.log("Bad body:", body);
            callback(null, {
              statusCode: 400,
              body: JSON.stringify({message: "invalid order"}),
              headers: {"Content-type": "application/json"}
            });
            return;
    }
    
    body = {
        pair: body.coin_pair,
        amount: body.size,
        price: body.price,
        side: body.side,
        type: body.type
    }
    
    getParameterFromSystemManager('bitbank-keys',callback)
    .then(function(data){
       
        apikey = data.split(",")[0];
        sercretKey = data.split(",")[1];
        
        var timestamp = Date.now().toString();
        var method = 'POST';
        var path = '/v1/user/spot/order';
        
        body = JSON.stringify(body);
        console.log(body)
        var text = timestamp + body;
        var sign = crypto.createHmac('sha256', sercretKey).update(text).digest('hex');
        
        var option = {
          url: 'https://api.bitbank.cc' + path,
          method: method,
          headers: {
            'ACCESS-KEY': apikey,
            'ACCESS-NONCE': timestamp,
            'ACCESS-SIGNATURE': sign,
            'Content-Type': 'application/json'
            },
          body: body
        }
        
        return sendRequest(option, callback);
    }).then(function(data){
        data = JSON.parse(data.body)
        console.log(data)
        callback(null, {
              statusCode: 200,
              body: JSON.stringify({message: data.data}),
              headers: {"Content-type": "application/json"}
            });
        return;
    });
    
    
    function checkElement(element){
        if(element.type == 'market' || element.type == 'limit'
        || element.type == 'stop'){
                
            if(element.side != 'buy' && element.side != 'sell'){
                console.log("invalid side");
                return false;
            }
            
            
            element.price = Number(element.price);
            element.size = Number(element.size);
            if(isNaN(element.price) && element.type != 'market'){
                console.log("number invalid:", element.price);
                return false;
            }
            if(isNaN(element.size)){
                console.log("number invalid:", element.size);
                return false;
            }
            
            return true;
        }
        return false;
    }
    
    function getParameterFromSystemManager(apikey_name, callback) {
    
        return new Promise(function (resolve) {
            var apikey = process.env[apikey_name];
            
            if(!apikey || typeof apikey == undefined){
            
                // Fetches a parameter called REPO_NAME from SSM parameter store.
                // Requires a policy for SSM:GetParameter on the parameter being read.
                var params = {
                    Name: apikey_name,
                    /* required */
                    WithDecryption:true
                };
                
                ssm.getParameter(params, function(err, apikey) {
                    if (err){
                        console.error(err.stack);
                        callback(null,{
                            statusCode: 500,
                            body: JSON.stringify({message: err.toString()}),
                            headers: {"Content-type": "application/json"}
                        });
                        resolve(null);
                        return;
                    }
                    process.env[apikey_name] = apikey.Parameter.Value;
                    resolve(apikey.Parameter.Value);
                });
            }else resolve(apikey);
        });
    }
    
    
    function sendRequest(option, callback){
        
        return new Promise(function (resolve) {
            request(option, function(error, response, body){
                    
                    if(error){
                        console.error(error);
                        callback(null,{
                            statusCode: 500,
                            body: JSON.stringify({message: error.toString()}),
                            headers: {"Content-type": "application/json"}
                        });
                        resolve(null);
                    }
                    var data = {response, body}
                    resolve(data);
            });
            });
    }
}

4. おわりに

AWS開発再開しているのでまた何か発見があれば載せます。