【AWS】bitflyerポジション表示

【きっかけ】

過去の記事参照
 
buffalokusojima.hatenablog.com


1. 使用するサービス

(AWS)

  • Lambda
  • IAM

(外部サービス)

bitflyer Lightning API

2. bitflyerからポジションを取得し表示する機能を簡単なのでフロントエンドとバックエンド両方説明します。

3. 実装
(バックエンド)
AWSのLambdaに実装。API Gatewayの設定とかは過去記事参照。
過去作ったLambdaと大差ないので説明は不要かと思います。ほど注文一覧取得とかと同じです。
buffalokusojima.hatenablog.com

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

exports.handler = (event, context, callback) => {
    
    getParameterFromSystemManager('bitflyer-keys',callback)
    .then(function(data){
       
        const apikey = data.split(",")[0];
        const sercretKey = data.split(",")[1];
        
        var timestamp = Date.now().toString();
        var method = 'GET';
        var path = '/v1/me/getpositions?product_code=FX_BTC_JPY';
        
        var text = timestamp + method + path;
        var sign = crypto.createHmac('sha256', sercretKey).update(text).digest('hex');
        
        var option = {
          url: 'https://api.bitflyer.jp' + path,
          method: method,
          headers: {
            'ACCESS-KEY': apikey,
            'ACCESS-TIMESTAMP': timestamp,
            'ACCESS-SIGN': sign,
            'Content-Type': 'application/json'
            }
        }
        
        return sendRequest(option, callback);
    }).then(function(data){
        
        if(data.response.statusCode != 200){
          console.error("Error:",data.response);
          callback(null, {
            statusCode: data.response.statusCode,
            body: JSON.stringify({message: data.response}),
            headers: {"Content-type": "application/json"}
          });
          return;
        }
        
        data = JSON.parse(data.body);
        
        if(data.length == 0){
            console.log('No data Found');
            callback(null,{
                statusCode: 200,
                body: JSON.stringify({message: 'No data Found'}),
                headers: {"Content-type": "application/json"}
            });
            return;
        }
        
        console.log(data)
        callback(null, {
            statusCode: 200,
            body: JSON.stringify({data: data}),
            headers: {"Content-type": "application/json"}
        });
        return;
    });
   
    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);
            });
            });
    }
};

(フロントエンド)
注文一覧上部に表示します。ポジションがない場合はそのメッセージを表示。
価格は全体の平均をとってます。参考程度です。

サイト読み込み時にgetPositionと言う関数を呼んでます。

function getStatus(){

            getOrders();
            getPosition();
        }

getPositionの中身です。
さらにコールバックでmakePositionListを呼んでいます。

function getPosition(){
            var data = {
                "method": "GET",
                "url": URL + "GetPositionStatus"
            }

            sendRequest(data, makePositionList, null);
        }

makePositionListの中身です。
基本的にサイドは一定なので最初のデータを参照しています。
価格は全体の平均、枚数は合計です。

function makePositionList(data){
            data = JSON.parse(data);
            var targetDiv = document.getElementById("positionArea");
            if(targetDiv.firstElementChild){
                targetDiv.removeChild(targetDiv.childNodes[0]);
            }

            var div = document.createElement('div');
            if(!data.data){
                
                div.style.textAlign = "center";
                div.innerText="No Position";
                targetDiv.appendChild(div);
                return;
            }

            var average_size=0;
            var average_price=0;
            
            var box = document.createElement('div');
            for(d of data.data){
                var side_area = document.createElement('span');
                side_area.innerText = d.side;
                box.appendChild(side_area);

                var price_area = document.createElement('span');
                price_area.innerText = d.price;
                average_price += Number(d.price);
                box.appendChild(price_area);

                var size_area = document.createElement('span');
                size_area.innerText=d.size;
                average_size += Number(d.size);
                box.appendChild(size_area)
            }

            average_price = average_price / data.data.length;
            
            var side_area = document.createElement('span');
            side_area.innerText = data.data[0].side;
            div.append(side_area)

            var price_area = document.createElement('span');
            price_area.innerText = average_price
            div.appendChild(price_area);

            var size_area = document.createElement('span');
            size_area.innerText=average_size;
            div.appendChild(size_area)

            targetDiv.append(div);

            targetDiv.appendChild(box);
        }

4. おわりに
実装するとこんな感じになります。

show_position
ポジション表示