主要仮想通貨取引所の手数料の一覧データを一括で取得してみた

# 趣旨
正確な手数料の把握はbotを作るのに必然になる割に、いちいち計算するのは楽しくないので自動で取得して計算できるようにしました。

結果的にはfeeはtierやVIPレベルで一括で決まっていることが多く、銘柄毎に手数料の数値を取得することにあまり意味はないと大分後になってから気づいて手数料の自動取得をメインのコードに組み込むことは途中で断念したんですが、本記事のコード自体はきちんと動作します。

# JavaScript 
JavaScriptを使います。
JavaScriptをサーバーサイドの言語のように扱うことのできるNode.JSを利用します。

https://ja.wikipedia.org/wiki/Node.js

仮想通貨Botterにとっては必要不可欠なライブラリであるCCXTはPythonよりもJavaScriptの方がドキュメントが詳しく書いてあるのと、Web3系のドキュメントもJavaScriptよりの言語で書かれてることが多いので多分Pythonと同時並行で習得した方が作業が楽になります。

以下のコマンドでnode.jsがインストールされているか確認し、インストールされている場合はCCXTライブラリをインストールします。
```
node -v
npm install ccxt
```
もしインストールされていない場合は以下のページからダウンロードします。

https://nodejs.org/

# コード（コピペ可能）
以下のコードについての説明は省略します。
結局このコードは使用しないと決めましたし、使い道も今のところないので省きます。

```javascript exchanges_fees.js
const fs = require('fs'); 
const ccxt = require('ccxt');

const configFile = 'config.json';
const configData = JSON.parse(fs.readFileSync(configFile, 'utf-8'));

async function fetchFees(apiKeyConfig) {
    try {
        const exchange = new ccxt[apiKeyConfig.exchange]({
            apiKey: apiKeyConfig.apiKey,
            secret: apiKeyConfig.secret,
            password: apiKeyConfig.password, 
        });

        let feesData = {}; 
        feesData[apiKeyConfig.exchange] = {}; 

        const markets = await exchange.loadMarkets();

        if (exchange.has.fetchTradingFees) {
            const fees = await exchange.fetchTradingFees();
            console.log(`Fees for ${apiKeyConfig.exchange}:`);
            Object.entries(fees).forEach(([marketSymbol, fee]) => {
                const type = markets[marketSymbol] && markets[marketSymbol].type ? markets[marketSymbol].type : 'unknown';
                console.log(`Exchange: ${exchange.id}, Market: ${marketSymbol}, Type: ${type}, Maker Fee: ${fee.maker}, Taker Fee: ${fee.taker}`);
                feesData[apiKeyConfig.exchange][marketSymbol] = { ...fee, type }; // Store fees data including type
            });
        } else if (exchange.has.fetchTradingFee) {
            console.log(`Fees for ${apiKeyConfig.exchange}:`);
            for (const [symbol, market] of Object.entries(markets)) {
                try {
                    const fee = await exchange.fetchTradingFee(symbol);
                    console.log(`Exchange: ${exchange.id}, Market: ${symbol}, Type: ${market.type}, Maker Fee: ${fee.maker}, Taker Fee: ${fee.taker}`);
                    feesData[apiKeyConfig.exchange][symbol] = { ...fee, type: market.type }; // Store fees data including type
                } catch (e) {
                    console.error(`Error fetching fee for market ${symbol}: ${e.message}`);
                }
            }
        } else {
            console.log(`The exchange ${apiKeyConfig.exchange} does not support fetching fees through CCXT.`);
        }

        fs.writeFileSync(`${apiKeyConfig.exchange}_fees.json`, JSON.stringify(feesData, null, 2), 'utf-8');
        console.log(`Fees data for ${apiKeyConfig.exchange} saved to ${apiKeyConfig.exchange}_fees.json`);

    } catch (e) {
        console.error(`Error fetching fees for ${apiKeyConfig.exchange}: ${e.message}`);
    }
}

async function main() {
    for (const apiKeyConfig of configData.apiKeys) {
        await fetchFees(apiKeyConfig);
    }
}

main();
```

:::note info
Pythonしか知らない場合はアロー関数や無名関数、非同期通信がわかりづらかったので自分の備忘録としても有益な参考動画を載せておきます。
:::

https://www.youtube.com/watch?v=Uqm642_O52U

https://www.youtube.com/watch?v=kbKIENQKuxQ&t=4s

## config.json
Configファイルを以下の形式でセットします。
取引所によってはパスワードまで必要です。
```json config.json
{
  "apiKeys": [
    {
      "exchange": "binance",
      "apiKey": "",
      "secret": ""
    },
    {
      "exchange": "okx",
      "apiKey": "",
      "secret": "",
      "password": ""
    },
    {
      "exchange": "bybit",
      "apiKey": "",
      "secret": ""
    },
    {
      "exchange": "bitget",
      "apiKey": "",
      "secret": "",
      "password": ""
    },
    {
      "exchange": "gate",
      "apiKey": "",
      "secret": ""
    }
  ]
}
```
以下のコマンドでプログラムを起動します。
```
node exchanges_fees.js
```