「為替レート」と「両替レート」の違いって?Rakuten RapidAPIのAPIでレートを取得してみる

f:id:ts0818:20211226110957j:plain

zuuonline.com

13日、ビットコインの総量のうち、90%以上が発行済みとなった。Bitcoin.comのデータによると、流通しているビットコインは現在、約1899万BTCとなる。

ビットコイン、2100万枚のうち90%が発行 2140年に全て採掘予定 | ZUU online

ビットコインプルーフ・オブ・ワーク(PoW)というコンセンサスアルゴリズムのもと稼働している。ビットコインは取引の承認作業を行うマイナーに報酬として付与されることで発行される。

ビットコイン、2100万枚のうち90%が発行 2140年に全て採掘予定 | ZUU online

当初、マイナー報酬は50BTCであったが、その後は報酬が半減する「半減期」を重ねたことで、現在は6.25BTCとなっている。次の半減期は2024年5月頃とされており、マイナー報酬は3.125BTCに減る。

ビットコイン、2100万枚のうち90%が発行 2140年に全て採掘予定 | ZUU online

こうした仕組みにより、ビットコインの新規発行スピードも減速していくため、上限の90%まで発行されるのに要した期間は実に約12年となった。

ビットコイン、2100万枚のうち90%が発行 2140年に全て採掘予定 | ZUU online

⇧ 12年とは壮大ですな...

なお、ビットコインは約4年に1度半減期を迎えるため、残り10%のビットコインが全てマイニングされるのは2140年頃と推測されている。

ビットコイン、2100万枚のうち90%が発行 2140年に全て採掘予定 | ZUU online

⇧ さらに20年ぐらいかかるのか...量子コンピューターとか発展して期間短縮されたりしないのかな?

今回は、異なる国の「通貨」に換算する際の「レート」の話とかです。

レッツトライ~。

「為替レート」と「両替レート」の違いって?

異なる国の「通貨」に変換して金額の計算とかをしないといけない場合に、「rate(レート)」を基準にするってことがあるあるだと思うのですが、

  • 為替レート
  • 両替レート

の違いって?

hotels.his-j.com

為替(かわせ)レート(Exchange rate)とは、為替相場とも呼び、外国為替市場(がいこくかわせしじょう)において異なる国の通貨を為替交換(手形・小切手・証書などで金銭の受け渡し)する際の、交換比率、または、取引相場を指します。一般的にこの「為替レート」は銀行間取引(インターバンク取引)のレートを指します。

為替(かわせ) レート/両替レート │ tripiteasy

海外旅行などで個人が銀行等で現金を異なる国の通貨に交換する際の「両替レート」は、外国為替市場における「為替レート」とは異なるものですが、「為替」という言葉に「交換、ひきかえ」という意味があることから「為替レート」を「両替レート」の意味として使うこともあります。英語ではどちらも「Exchange rate」です。

為替(かわせ) レート/両替レート │ tripiteasy

⇧ う~ん、英語圏だと、どちらも「Exchange rate」って言葉になるらしい...、紛らわしいっすな。

 

楽天さんの「Rakuten RapidAPI」とは?

ドキュメントによりますと、

api.rakuten.co.jp

Rakuten RapidAPIは、開発者がAPIを検索・接続し、利用状況を管理できるAPIマーケットプレイスです。ご自身のプロジェクトに必要なAPIを検索してアプリに埋め込み、ダッシュボードでAPIの利用状況が一括管理できます。また、APIプロバイダの方は、Rakuten RapidAPIを活用することで、自社のAPIを数十万といるRakuten RapidAPIのアクティブ開発者に公開することができます。

https://api.rakuten.co.jp/docs/ja/docs/what-is-rapidapi/

Rakuten RapidAPIでのAPIの利用はとても簡単です。APIはREST形式で提供されるため、分かりやすく、簡単にアプリに埋め込むことができます。また、ダッシュボードを用いて利用中のAPIの状況(APIコール数、レイテンシ、エラー率など)を一括管理できるようになっています。詳しくは、「基本事項 - 初めてのAPIコール」セクションか、RakutenRapid APIの開発者向けページよりご確認ください。

https://api.rakuten.co.jp/docs/ja/docs/what-is-rapidapi/

⇧ ということで、アプリケーションなどで利用できる「API」らしい。

元々「APIマーケットプレイス」を提供してたのは、

corp.rakuten.co.jp

 楽天株式会社(本社: 東京都世田谷区、代表取締役会長兼社長: 三木谷 浩史、以下「楽天」)は、米国でAPI(注1)マーケットプレイス「RapidAPI」を提供するR Software, Inc.社(本社:米国カリフォルニア州、創業者兼最高経営責任者:イド・ジノ、以下「R Software」)と、共同でAPIマーケットプレイス「Rakuten RapidAPI」を提供する独占的な戦略パートナー契約を締結しましたのでお知らせします。

楽天、「RapidAPI」を提供する米国R Software社と 独占的戦略パートナー契約を締結 | 楽天グループ株式会社

⇧ 別の会社だったようですね。

なんか、

api.rakuten.net

Live currency and foreign exchange rates by specifying source and destination quotes and optionally amount to calculate. Support vast amount of quotes around the world.

https://api.rakuten.net/fyhao/api/currency-exchange/endpoints

⇧「通貨」の換算に必要な「レート」を取得してくれるAPIを公開してくれてる模様。

しかも、無料でrequest無制限とか、『シンジラレナ~イ(トレイ・ヒルマン)』。

f:id:ts0818:20211225184441p:plain

「Rakuten RapidAPI」のAPIを利用するには、まずは、「Rakuten RapidAPI」への「アカウント」登録が必要のようです。

GitHubアカウント」や「Gmailアカウント」とかでもOKっぽいようなので、今回は「新規登録:Github」を選びました。

f:id:ts0818:20211225185256p:plain

「Authorize RapidAPI」を押下。

f:id:ts0818:20211225185352p:plain

「フルネーム」を入力して「完了」しました。(「フルネーム」はニックネームとかでも良いのかも)

f:id:ts0818:20211225185505p:plain

ハンバーガーメニュー」を押下して、

f:id:ts0818:20211225190050p:plain

「プロファイル」を押下して、

f:id:ts0818:20211225185920p:plain

自分のアカウントが登録されていれば、「Rakuten RapidAPI」への「アカウント登録」が完了したってことらしい。(自分の場合は、「GitHubアカウント」で登録したので、以下のような表示になってました。)

f:id:ts0818:20211225190150p:plain

 

「Rakuten RapidAPI SDk」のインストールはしなくてもOKっぽい

「Rakuten RapidAPI」を利用するために、各プログラミング言語向けの「SDK(Software Development Kit)」が公開されてるらしく、

api.rakuten.co.jp

Rakuten RapidAPIでは、マーケットプレイス上のすべてのAPIに接続できるSDK「Rakuten RapidAPI SDK」を用意しています。お気に入りのプログラミング言語が何であるかにかかわらず、アプリケーションでRakuten RapidAPIを簡単に利用することができます。Rakuten RapidAPIでは以下の言語でSDKを用意しています。

https://api.rakuten.co.jp/docs/ja/docs/getting-started-with-rapidapi-sdks/

• Node.js • Java
• PHP • Objective-C
• Python • .NET
• Ruby  

ご利用のプログラム言語でサポートされていない言語があれば、support-rakuten-rapidapi@mail.rakuten.com までお問い合わせください。

https://api.rakuten.co.jp/docs/ja/docs/getting-started-with-rapidapi-sdks/

⇧ 現状、上記のプログラミング言語をサポートしてくれてる模様、しかも、上記に掲載されてない言語については問い合わせください、とあるので、もしかしたら、何とかしてくれるかもな展開がありそうですかね。

とりあえず、Javaの「SDK」を確認してみることに。

api.rakuten.co.jp

⇧ 上記の説明によりますと、

  • com.mashape.unirest/Unirest Java

の「依存関係」を追加する必要があるらしいのですが、

f:id:ts0818:20211225192325p:plain

⇧ なんか、「Vulnerabilities」に列挙されてる脆弱性の対応が終わってるのかが分からない...

なんか、でも、

orablogs-jp.blogspot.com

Oracleさんのブログで、「Unirest Java」普通に使ってるから問題ないってことなんかな?

ただ、上記のOracleさんのブログの記事が、2018年頃で、それ以降にも脆弱性が出てるらしいので判断が付きませんですな...

API」の「サブスクリプション登録」と「APIキー」があれば「API」は実行可能の模様

その前に、

api.rakuten.co.jp

⇧ 上記の説明によると、利用したい「API」のページで「プラン」の中の「接続する」をクリックして、「サブスクリプション登録」が必要らしい。

今回利用しようとしてた「Currency Exchange」って「API」は「無料」で且つ「無制限」なのがありがたいですな。

f:id:ts0818:20211225201842p:plain

そうすると、「API」が利用できる状態になったらしく、

f:id:ts0818:20211225201803p:plain

ちなみに、「開発者ボード」のタブの左サイドバーの中から「支払情報」>「サブスクリプション及び使用量」を選択すると、現在契約中の「API」が確認でき、利用するのを止めたくなった場合は、「サブスクライブの解除」をすれば大丈夫かと。

f:id:ts0818:20211226101754p:plain

話を「Currency Exchange」のAPIに戻して、「コードスニペット」で「(Java)OkHttp」って選択してみたところ、「x-rapidapi-key」が設定されていたのだけど、これが「APIキー」らしく、「API」を実行するのに必要ということらしい。

f:id:ts0818:20211225202624j:plain

⇧「テスト」を押下した結果、

["SGD","MYR","EUR","USD","AUD","JPY","CNH","HKD","CAD","INR","DKK","GBP","RUB","NZD","MXN","IDR","TWD","THB","VND"]

f:id:ts0818:20211225203640p:plain

全部で19か国の「通貨」に対応しているということですかね、まぁ、無料で利用できるとなるとやはり制限はあるということでしょうかね。

もう1つの「GET exchange」ってほうを、「JPY」から「USD」の設定で「テスト」してみたところ、

f:id:ts0818:20211225204601p:plain

ということで、「0.008744」という結果になったのですが、

www.xe.com

f:id:ts0818:20211225204846p:plain

⇧ 上記のサイト様で「1 JPY = 0.00874027 USD」となってることから、「レート」の精度も概ね問題なさそうですと。

「仲値レート」とは?

www.smbcnikko.co.jp

仲値とは、金融機関が外国為替取引をする際の基準となるレートのことです。TTM(Telegraphic Transfer Middle Rate)ともいい、金融機関が毎朝9時55分の為替レートを参考に決定します。海外旅行に行く際、日本円を外貨に両替するときのレートと、外貨を日本円に戻すときのレートに開きがありますが、そのちょうど中間に位置するのが仲値です。

仲値│初めてでもわかりやすい用語集│SMBC日興証券

⇧ タイムラグで「通貨」を換算する時の「レート」が変わってしまうので、間を取るということらしい。

脱線しましたが、Eclipseで「Spring Boot」プロジェクト(「ビルドツール」は「Gradle」を使用)を作成して「Rakuten RapidAPI」の「Currency Exchange」ってAPIを試してみます。

f:id:ts0818:20211225230417p:plain

ファイルの中身は、以下のようになりました。(「APIキー」などはご自分の環境に合わせてください。)

APIキー」は、「Rakten RpidAPI」にログイン後、「開発者ボード」タブを選択し、左サイドバーから該当する「アプリケーション」の「セキュリティ」を選ぶと「キー」という項目があり、「キー」が「APIキー」のことらしいです。

「キー」のinputエリアの横の目玉マークをクリックすると、「APIキー」の値が確認できます。

f:id:ts0818:20211226123609j:plain

「Rakten RpidAPI」の「アプリケーション」が1つも無いときは、初回の「API」の「サブスクリプション登録」で、自動的に1つ「アプリケーション」が作られるみたい。(今回だと「Currency Exchange」の「API」の「サブスクリプション登録」の際に「アプリケーション」が作成され、「APIキー」が払い出された模様)

なので、この「APIキー」で、他の「API」も実行できる気はする、もちろん、「API」毎に「サブスクリプション登録」は必要になるはずだけど。

APIキー」の詳細は、

api.rakuten.co.jp

⇧ドキュメントを確認ください。

■/rakten-api/build.gradle

plugins {
	id 'org.springframework.boot' version '2.6.2'
	id 'io.spring.dependency-management' version '1.0.11.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
	mavenCentral()
}

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	// https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp
    implementation group: 'com.squareup.okhttp3', name: 'okhttp', version: '5.0.0-alpha.3'
	// https://mvnrepository.com/artifact/org.json/json
	implementation group: 'org.json', name: 'json', version: '20211205'
	// https://mvnrepository.com/artifact/org.projectlombok/lombok
	compileOnly group: 'org.projectlombok', name: 'lombok', version: '1.18.22'
	testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

test {
	useJUnitPlatform()
}

■/rakten-api/src/main/java/com/example/demo/service/RateService.java

package com.example.demo.service;

import java.util.List;

public interface RateService {

	public List<String> executeListQuotes();
	public String executeExchangeApi(String fromCurrency, String toCurrency, String amount) ;

}

■/rakten-api/src/main/java/com/example/demo/service/impl/RateServiceImpl.java 

package com.example.demo.service.impl;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import org.springframework.stereotype.Service;

import com.example.demo.service.RateService;

import lombok.extern.log4j.Log4j2;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;

@Log4j2
@Service
public class RateServiceImpl implements RateService {

  @Override
  public List<String> executeListQuotes() {
    // TODO 自動生成されたメソッド・スタブ
    return null;
  }

  @Override
  public String executeExchangeApi(String fromCurrency, String toCurrency, String amount) {
    if (Objects.isNull(fromCurrency) || Objects.isNull(toCurrency) || Objects.isNull(amount)) {
      log.info("fromCurrency=" + fromCurrency + "toCurrency=" + toCurrency + "amount=" + amount);
      return "不正な通貨を指定しています";
    }
    String requestUrl = new StringBuilder("https://currency-exchange.p.rapidapi.com/exchange")
        .append("?from=")
        .append(fromCurrency)
        .append("&to=")
        .append(toCurrency)
        .append("&q=")
        .append(amount)
        .toString();

    final Request.Builder builder = new Request.Builder();

    // set headers
    Map<String, String> httpHeaderMap = new HashMap<>();
    httpHeaderMap.put("x-rapidapi-key", "Rakten RapidAPIで生成されたAPIキーの値");
    httpHeaderMap.forEach(builder::addHeader);

    Request request = builder
        .url(requestUrl)
        .get()
        .build();

    OkHttpClient client = new OkHttpClient.Builder()
        .build();

    try (Response response = client.newCall(request).execute();) {
      log.info("HTTP STATUS CODE: " + response.code());
      String rate = response.body().string();
      StringBuilder sb = new StringBuilder();
      sb.append("【レート( ")
          .append(fromCurrency)
          .append(" exchange ")
          .append(toCurrency)
          .append(")】 ")
          .append(rate)
          .append("<br>")
          //.append(System.lineSeparator());
          .append("【日時:Asia/Tokyo(JST:Japan Standard Time)】")
          .append(OffsetDateTime.now(ZoneId.of("Asia/Tokyo")))
          .append("<br>")
          .append("【日時:America/New_York(UTC:Coordinated Universal Time)】")
          .append(OffsetDateTime.now(ZoneId.of("America/New_York")))
          .append("<br>")
          .append("【換算後金額】")
          .append(amount)
          .append(fromCurrency)
          .append("= ")
          .append(fromCurrencyAmountCovertToCurrencyAmount(rate, amount))
          .append(toCurrency);
      return sb.toString();
    } catch (IOException e) {
      // TODO 自動生成された catch ブロック
      e.printStackTrace();
    }
    return null;
  }

  private String fromCurrencyAmountCovertToCurrencyAmount(String rate, String fromCurrencyAmount) {
    if (Objects.isNull(rate) || Objects.isNull(fromCurrencyAmount)) {
      log.info("rate=" + rate + "fromCurrencyAmount=" + fromCurrencyAmount);
      return "";
    }
    return (new BigDecimal(rate).multiply(new BigDecimal(fromCurrencyAmount))).toString();
  }
}

■/rakten-api/src/main/java/com/example/demo/controller/RateController.java

package com.example.demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.example.demo.service.RateService;

@RestController
@RequestMapping("/rate")
public class RateController {

  @Autowired
  private RateService rateService;

  @GetMapping
  public String index() {
    return "";
  }

  @GetMapping("/research")
  public String researchRate(
      @RequestParam("from") String fromCurrency,
      @RequestParam("to") String toCurrency,
      @RequestParam("q") String amount) {
    return rateService.executeExchangeApi(fromCurrency, toCurrency, amount);
  }

}    

■/rakten-api/src/main/java/com/example/demo/RaktenApiApplication.java

package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class RaktenApiApplication {

  public static void main(String[] args) {
    SpringApplication.run(RaktenApiApplication.class, args);
  }

}    

で、実行。

f:id:ts0818:20211226100554p:plain

で、ブラウザから「http://localhost:8080/rate/research?from=JPY&to=USD&q=1000」にアクセスすると、レートと、換算された金額が出力できました。

f:id:ts0818:20211226100430p:plain

⇧ 時間が経って、レートも変わってますが、換算できたようです、日本の1000円がアメリカの8.741000ドルということで。

なんだかんだで、「Currency Exchange」の「API」を25回使ってるという、無制限じゃなかったら怖くて試行錯誤できないですな...

f:id:ts0818:20211226102514p:plain

似たようなサービスでも、「Freeプラン」はあるらしいのですが、

wellknowledge.org

⇧ 上記サイト様によりますと、「API」の回数制限はあるという。

それにしても、

rapidapi.com

To reiterate, the Google Finance API is no longer supported by Google so it’s undocumented and unreliable. Therefore, this API is best for private toy applications.

https://rapidapi.com/blog/google-finance-api-alternatives/

⇧そもそも「Google Finance API」ってものがあったのを知らなかったのだけど、

www.weblog-life.net

uxbear.me

support.google.com

⇧ まさかの2011年に提供終了されてたというね...

2021年12月26日(日)現在は、「Google SpreadSheet」で用意されてる「GOOGLEFINANCE」関数を経由して取得する感じになるらしい。

プログラム的には「Sheets APIGoogle Sheets API)」を利用していく感じになるのかな?なんか、めちゃくちゃ実装が面倒くさそうになる気が...

まぁ、どれだけの「通貨」に対応しなければいけないかによって、利用する「API」も変えていかないとですかね...。

なんか、「Rakuten RapidAPI」で、

api.rakuten.net

⇧ 他にも、『無料、且つ、無制限』で使える「レート取得」系の「API」はあったけども、いつまで『無料、且つ、無制限』で提供してくれるのかは不明です。

過去の「レート」とか取得する必要がある場合なんかも考慮しないといけないケースもあったりなかったり。

「通貨」の「レート」と関係ないですが、

api.rakuten.net

⇧「仮想通貨」に関する情報を取得できる「API」とかも『無料、且つ、無制限』で提供してくれてるようです。

ちなみに、「ZoneId」の一覧については、

stackoverflow.com

mkyong.com

⇧ 自分で頑張って、取得する感じになるみたいね...

毎回モヤモヤ感が半端ない...

今回はこのへんで。