AWS LambdaとGolangを用いてサーバーレスなビットコイン積立アプリケーションをクラウド上に構築した話

# 概要
ビットコイン（や他の暗号資産）を定期的に購入するようなアプリケーションを開発しました。暗号資産取引所(bitflyer)のAPIを定期的にコールするようなアプリケーションを開発し、クラウドインフラ（AWS）上で運用を行っています。

ソースコードは以下です。
↓↓↓
https://github.com/Kohei-Sato-1221/reserve-bitcoin-lambda

# アプリケーションのアーキテクチャ
- AWSのクラウドインフラを用いて以下のようなアプリケーションを構築しました。

![architecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454171/1c91f84b-49d5-9d21-d680-5ef3c76263ed.png)



# 技術スタック
|名称|説明|
|--|--|
|AWS Lambda|サーバーレスアプリケーションを実現。Lambda関数で取引所のAPIをコールします。|
|Golang|Lambda関数はGolangで実装を行いました。|
|SAM(Serverless Application Model)|ローカルでLambdaの開発を行う際に使用。関数の雛形作成・関数のローカルでのエミュレート・関数のデプロイを行います。|
|Event Bridge|Lambda関数を定期的に実行する役割。|
|System manager（パラメータストア）|アプリケーションが使用するパラメータを格納。Lambdaがパラメータを取得します。|

# アプリ開発の経緯
2021年に**ビットコインの価格は６００万円台**に達し、暗号資産は投資の対象として非常に注目度が高まっています。しかし、暗号資産の[ボラティリティ](https://www.smbcnikko.co.jp/terms/japan/ho/J0280.html)は大きいので、一回の注文で多額の暗号資産を購入してしまうと、大きな含み損が発生してしまう可能があります。

そこで、少額の暗号資産を定期的に購入することで、価格変動のリスクを避けるような購入をしたいと考えました。まさに、[ドルコスト平均法](https://hoken.niaeru.com/media/investment/dollar-cost-averaging/)の考え方を適応したわけです。

# なぜ既存の積立機能を使わないのか？
bitflyerやCoinCheckなどでは、ビットコインの積立機能を提供しています。しかし、私はあえてこのようなアプリケーションを実装しました。理由は、価格の点です。既存の積立機能は、基本的に販売所の価格となっており、板取引で購入できる金額よりも手数料が上乗せされています。**取引所で暗号資産を取引したほうが安く入手できる**のです。


# 技術的な解説
以下ではアプリケーションをどのような手順で構築したか解説します。

## SAM(Serverless Application Model)の導入
SAMとはLambdaのようなサーバーレスアプリケーションの開発する際に役に立つ便利ツールです。これを使えば、Lambda関数の雛形を作成したり、Lambda関数をローカルでエミュレートしたりする（わざわざデプロイしなくても挙動が確認できる）ことができます。

`AWS SAM CLI`をローカルPCにインストールして、Lambdaの実装を開始しました。


## 新規注文APIをコールするLambda関数の実装
[bitflyerのAPI](https://lightning.bitflyer.com/docs?lang=ja#%E6%96%B0%E8%A6%8F%E6%B3%A8%E6%96%87%E3%82%92%E5%87%BA%E3%81%99)をコールする機能をLambdaに実装しました。

```go
func (client *APIClient) PlaceOrder(order *Order) (*OrderRes, error) {
	method := "POST"
	path := "/v1/me/sendchildorder"
	url := baseURL + path
	data, err := json.Marshal(order)
	if err != nil {
		return nil, err
	}

	header := client.getHeader(method, path, data)

	res, err := utils.DoHttpRequest(method, url, header, map[string]string{}, data)
	if err != nil {
		return nil, err
	}

	var orderRes OrderRes
	err = json.Unmarshal(res, &orderRes)
	if err != nil {
		return nil, err
	}

	if len(orderRes.ChildOrderAcceptanceId) == 0 {
		return nil, errors.New(string(res))
	}

	return &orderRes, nil
}
```

## APIキー・APIシークレットキーの扱い
取引所の注文を行うには取引所の`APIキー・APIシークレットキー`が必要になります。Lambda関数にはハードコーディングせずに外部に格納するようにしました。AWSには`Systems Manager パラメータストア`という機能があります。このサービスに取引所のAPIキーやAPIシークレットを格納し、アプリケーション実行時にパラメータを取得しています。

```go
	apiKey, err := getParameter("buy-btc-apikey")
	if err != nil {
		return getErrorResponse(err.Error()), err
	}
	apiSecret, err := getParameter("buy-btc-apisecret")
	if err != nil {
		return getErrorResponse(err.Error()), err
	}
```

## Event Bridgeによるスケジューリング
`Event Bridge`というサービスではCron式を指定して、Lambdaの起動スケジュールを設定できます。 1日に１回、特定の時間にLambdaが起動するように設定しました。

![スクリーンショット 2021-04-03 16.09.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454171/aba41c2a-d6d3-1735-9235-ca0e9d2379f1.png)

# Udemyで講座を公開しました
こちらのアプリケーションの構築方法をUdemyの講座として公開しています。
暗号資産（仮想通貨）の基礎の解説や環境構築のハンズオン・ライブコーディングがまとまった教材となっております。

https://www.udemy.com/course/bitcoin-lambda-golang/?referralCode=674B788BFA80A564B9EA

プロモーションコード欲しい方は、気軽にご連絡ください！