【node.js】Coincheck APIを活用した自動売買Botの開発実践ガイド

## はじめに

KG-7thの後藤です。

GWは有休を使いまくって2週間ほどお休みをいただきました。
時間あるしちょっと前から気になっていた仮想通貨に手ェ出してみるか。。と思った次第です。
（働きたくないでござる）

今回の記事ではコインチェックのAPIを使って購入・売却する方法について記載します。

## コインチェックについて

今回コインチェックを選んだのは、取引所での仮想通貨のやり取りであれば
手数料がごくわずかで済むというところに注目したからです。

ただしスプレッドは発生します。
販売所方式ではスプレッド（売値と買値の差）が発生しますが、それも大きくはないらしい。

## 今回作成するアプリの概要

**基本仕様**
- 開発言語：Node.js + TypeScript
- 取引通貨：ETH/JPY（取引所方式）
- 主要機能：
  - 3種類の売買戦略実装
  - 自動注文実行

## コード解説

コインチェックへのリクエストにはaxiosを使いました。

### axiosの初期化

```ts
  // axiosインスタンスを事前設定
  private axiosInstance = axios.create({
    baseURL: this.ENDPOINT,
    headers: {
      'Content-Type': 'application/json',
    }
  });
```

### リクエスト処理

```ts
  /**
   * 統合リクエストメソッド
   * @param method HTTPメソッド
   * @param path APIエンドポイントパス
   * @param data リクエストボディ
   * @returns レスポンスデータ
   */
  async request<T>(method: Method, path: string, data?: any): Promise<T> {
    const nonce = Date.now().toString();

    // 署名生成
    const signature = await this.generateSignature(
      nonce,
      path,
      data ? JSON.stringify(data) : ''
    );

    // axios設定オブジェクト
    const config: AxiosRequestConfig = {
      method,
      url: path,
      headers: {
        'ACCESS-KEY': this.accessKey,
        'ACCESS-NONCE': nonce,
        'ACCESS-SIGNATURE': signature,
      },
      data // POST用ボディ
    };

    try {
      const response = await this.axiosInstance.request<T>(config);

      // ステータスコード200以外はエラー扱い
      if (response.status !== 200) {
        throw new Error(`HTTP Error: ${response.status}`);
      }

      return response.data;
    } catch (error) {
      // エラー詳細をログ出力
      if (axios.isAxiosError(error)) {
        console.error('API Error Details:', {
          status: error.response?.status,
          data: error.response?.data,
          config: error.config
        });
      }
      throw new Error(`API request failed: ${error}`);
    }
  }
  ```

  ### 署名の生成

  リクエストでデータを暗号化する必要があるため、
  以下の形でシークレットキーを使った暗号化を行っています

  ```ts
  /**
   * 署名生成関数（非同期化）
   * @param nonce タイムスタンプ
   * @param path APIエンドポイントパス
   * @param body リクエストボディ
   * @returns 署名文字列
   */
  private async generateSignature(nonce: string, path: string, body: string): Promise<string> {
    const message = nonce + this.ENDPOINT + path + body;
    return crypto
      .createHmac('sha256', this.secretKey)
      .update(message)
      .digest('hex');
  }
  ```

  ### 現在価格の取得

クエリで指定しているpairの値は使いたい仮想通貨によって変わります。
コインチェックのAPIドキュメントに書いてありました。

  ```ts
  // イーサリアム現在価格取得
  async getEthPrice(): Promise<number> {
    const ticker = await this.request<EthPriceEntity>('GET', '/ticker?pair=eth_jpy');
    console.log('ETH Price:', ticker);
    return ticker.last;
  }
  ```
### 注文作成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4042336/9b46c886-e91e-45f6-a0fc-f0d25ea393fa.png)

- rate：注文価格
- amount：注文量

```ts
type OrderType = 'buy' | 'sell';
type OrderParams = {
      rate: number;
      amount: number;
      order_type: OrderType;
      pair: 'eth_jpy';
};
  ```

  ```ts
  // 注文作成（取引所方式）
  async createOrder(params: OrderParams): Promise<any> {
    return this.request('POST', '/exchange/orders', params);
  }

  ```

## 終わりに

以下のリポジトリで利用しています

https://github.com/undo-works/AutoCrypto-Node