仮想通貨APIで発注してみる

# 前回
https://qiita.com/noritama08/items/11605e024d01e2cc1d9a

前回に続き、GMOコインのAPI(Node.js)で遊びます。
前回: APIで情報を参照
今回: APIで注文を入れてみる
# 注文を入れる
### 方針
private APIの「注文」を参考にする

https://api.coin.z.com/docs/?javascript#order

- レバレッジをかけず
= 現物取引
- 金額を指定
= 指値
を満たす様サンプルを書き換える
### 実装
```order.js
const axios  = require('axios');
const crypto = require('crypto');

const apiKey    = 'YOUR_API_KEY';
const secretKey = 'YOUR_SECRET_KEY';

const timestamp = Date.now().toString();
const method    = 'POST';
const endPoint  = 'https://api.coin.z.com/private';
const path      = '/v1/order';

// httpリクエストボディ作成
const reqBody   = JSON.stringify({
    // BTC:ビットコイン現物取引
    symbol: "BTC",
    // BUY/SELL
    side: "BUY",
    // 注文タイプ MARKET:成行, LIMIT:指値, STOP:逆指値
    executionType: "LIMIT",
    // 執行数量条件 FAS:一部約定後に残りの注文を有効とする
    timeInForce: "FAS",
    // 注文レート(円)
    price: "5514000",
    // 取引数量
    size: "0.0001"
})

// httpリクエストヘッダー作成
const text = timestamp + method + path + reqBody;
const sign = crypto.createHmac('sha256', secretKey).update(text).digest('hex');
const options = {
    "headers": {
        "API-KEY": apiKey,
        "API-TIMESTAMP": timestamp,
        "API-SIGN": sign
    }
};

// httpリクエスト送信
axios.post(endPoint + path, reqBody, options)
  .then(function (response) {
    console.log(response.data);
  })
  .catch(function (error) {
    console.log(error);
  });
```
リンク先APIサンプル通りのレート:430,001円で発注すると
エラーで返される。　<ソンナニ安ク売ラナイヨ
```
> node order.js
{
  status: 1,
  messages: [ { message_code: 'ERR-5121', message_string: 'Too low price.' } ],
  responsetime: '2024-06-05T14:20:56.966Z'
}
```
これは発注時に制限値幅を満たす必要がある為。

>注文レートが、「発注時点での現在値 ± 50%」の範囲外である

GMOコインでは制限値幅は上記と記載があるので、試行時の現在値:11,026,320円を元に指定すると問題なく注文が通る。
```
> node order.js
{
  status: 0,
  data: '4845091817',
  responsetime: '2024-06-05T14:21:15.125Z'
}
```

(参考)制限値幅

https://support.coin.z.com/hc/ja/articles/360001765227-%E6%B3%A8%E6%96%87%E6%99%82-%E7%B4%84%E5%AE%9A%E6%99%82%E3%81%AE%E4%BE%A1%E6%A0%BC%E5%88%B6%E9%99%90%E3%81%A8%E3%81%AF#:~:text=%E5%BD%93%E7%A4%BE%E3%81%AE%E5%8F%96%E5%BC%95%E6%89%80%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9,%E3%81%8C%E8%A8%AD%E3%81%91%E3%82%89%E3%82%8C%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82&text=%E4%BE%8B%EF%BC%89%E3%80%8C%E7%99%BA%E6%B3%A8%E6%99%82%E7%82%B9%E3%81%AE%E7%8F%BE%E5%9C%A8,%E3%81%94%E7%99%BA%E6%B3%A8%E3%81%84%E3%81%9F%E3%81%A0%E3%81%91%E3%81%BE%E3%81%9B%E3%82%93%E3%80%82

# 先ほどの発注状況を確認する
同様にAPIサンプルを元に注文照会を実装する。
```check.js
const axios  = require('axios');
const crypto = require('crypto');

const apiKey    = 'YOUR_API_KEY';
const secretKey = 'YOUR_SECRET_KEY';

const timestamp  = Date.now().toString();
const method     = 'GET';
const endPoint   = 'https://api.coin.z.com/private';
// 注文照会
const path       = '/v1/activeOrders';
const parameters = '?symbol=BTC&page=1&count=10';

const text = timestamp + method + path;
const sign = crypto.createHmac('sha256', secretKey).update(text).digest('hex');
const options = {
    "headers": {
        "API-KEY": apiKey,
        "API-TIMESTAMP": timestamp,
        "API-SIGN": sign
    }
};

axios.get(endPoint + path + parameters, options)
  .then(function (response) {
    // console.log(response.data);
    console.log(response.data.data);
  })
  .catch(function (error) {
    console.log(error);
  });
```
```console.log(response.data)の場合
> node check.js
{
  status: 0,
  data: { list: [ [Object] ], pagination: { count: 10, currentPage: 1 } },
  responsetime: '2024-06-05T14:25:08.582Z'
}
```
これを元に
```console.log(response.data.data)の場合
> node check.js
{
  list: [
    {
      executedSize: '0',
      executionType: 'LIMIT',
      losscutPrice: '0',
      orderId: 4845091817,
      orderType: 'NORMAL',
      price: '5514000',
      rootOrderId: 4845091817,
      settleType: 'OPEN',
      side: 'BUY',
      size: '0.0001',
      status: 'ORDERED',
      symbol: 'BTC',
      timeInForce: 'FAS',
      timestamp: '2024-06-05T14:21:15.205Z'
    }
  ],
  pagination: { count: 10, currentPage: 1 }
}
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214861/f58fcd98-b7d9-9e9c-90e6-f00cc1b27357.png)
注文時のリクエストパラメータ、画面上の注文照会と内容の一致が確認できた。

# 注文を変更する
```index_edit.js
const axios  = require('axios');
const crypto = require('crypto');

const apiKey    = 'YOUR_API_KEY';
const secretKey = 'YOUR_SECRET_KEY';

const timestamp = Date.now().toString();
const method    = 'POST';
const endPoint  = 'https://api.coin.z.com/private';
const path      = '/v1/changeOrder';
const reqBody   = JSON.stringify({
    // 対象にしたい注文ID ★
    orderId: 4845091817,
    // 変更後価格
    price: "1200"
})

const text = timestamp + method + path + reqBody;
const sign = crypto.createHmac('sha256', secretKey).update(text).digest('hex');
const options = {
    "headers": {
        "API-KEY": apiKey,
        "API-TIMESTAMP": timestamp,
        "API-SIGN": sign
    }
};

axios.post(endPoint + path, reqBody, options)
  .then(function (response) {
    console.log(response.data);
  })
  .catch(function (error) {
    console.log(error);
  });
```
★の箇所で先ほどの注文IDを指定し、希望の価格を指定するも制限値幅の範囲外の為エラーで返される。
```
> node index_edit.js 
{
  status: 1,
  messages: [ { message_code: 'ERR-5121', message_string: 'Too low price.' } ],
  responsetime: '2024-06-06T12:41:57.790Z'
}
```
調整すると price: "5599999"
```
> node index_edit.js 
{ status: 0, responsetime: '2024-06-06T12:48:25.097Z' }
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214861/1c538681-e8f3-d225-3ff1-566c4a5a819d.png)
反映された。

# 注文を取り消す
長くなってきたのでソースは割愛して、同じ注文IDを指定すると
```
> node index_cancel.js
{ status: 0, responsetime: '2024-06-06T12:52:43.678Z' }
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214861/b1d3af15-a6ea-309b-3351-0302d35bbe70.png)

# 約定状況を確認する
#### 約定
出した有効な注文(期間内)に、同じ金額の反対注文がマッチングされ取引が成立する事

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214861/52b50aa7-569d-2b39-0199-21063e1d4315.png)
約定済みのこちらの参照を試みる。

コードは割愛サンプルのうち以下を編集
・const parameters = '?orderId=4845036553'; //注文ID指定
・console.log(response.data.data);
```
> node index_commit.js
{
  list: [
    {
      executionId: 909168958,
      fee: '1',
      lossGain: '0',
      orderId: 4845036553,
      price: '82.325',
      settleType: 'OPEN',
      side: 'BUY',
      size: '3',
      symbol: 'XRP',
      timestamp: '2024-06-05T14:00:29.493Z'
    }
  ]
}
```
画面上の表示に一致する様に見える。