【仮想通貨】Cryptowatch Public Market REST API を眺める

キャバ嬢に

「リップル買っちゃった。名前がかわいいし。」

などと言われて即全てを手放しました、おはようございます。

そんな下落が止まらない仮想通貨たち。

仮想通貨全体の上げ下げを把握することができます。

Cryptowatch - live Bitcoin price charts

ここではAPIにてリアルタイムな情報を公開しています。

無料では当然制限はついてきますが。

Public Market REST API - Cryptowatch

いくつか簡単にデータを取得してみましょう。

Prices

Returns the current price for all supported markets. Some values may be out of date by a few seconds.

Example: https://api.cryptowat.ch/markets/prices

価格です。量が多いので日本円絡みのものだけ見てみます。


~ $ curl -s https://api.cryptowat.ch/markets/prices | jq "." | grep jpy
    "bitflyer:btcfxjpy": 990450,
    "bitflyer:btcjpy": 980519,
    "bitflyer:btcjpy-biweekly-futures": 984440,
    "bitflyer:btcjpy-weekly-futures": 984750,
    "bitmex:btcjpy-quarterly-futures": 9342,
    "kraken:btcjpy": 980085,
    "kraken:ethjpy": 102171,
    "kraken:repjpy": 0,
    "kraken:xrpjpy": 0,
    "kraken:zecjpy": 0,
    "quoine:bchjpy": 139770.97,
    "quoine:btcjpy": 1010138.75,
    "quoine:ethjpy": 107000,

いくつかは価格が「0」となっていますが。

JSON形式で、項目としては


"(取引所):(通貨ペア)": 価格円

が取得できるようです。

もうひとつみてみます。

Asset
Returns a single asset. Lists all markets which have this asset as a base or quote.

Example: https://api.cryptowat.ch/assets/btc

こちらでは以下のようなものが取得できます。


~ $ curl -s https://api.cryptowat.ch/assets/jpy | jq '.'
{
  "result": {
    "id": 104,
    "symbol": "jpy",
    "name": "Japanese Yen",
    "fiat": true,
    "markets": {
      "quote": [
        {
          "id": 89,
          "exchange": "kraken",
          "pair": "btcjpy",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/kraken/btcjpy"
        },
        {
          "id": 100,
          "exchange": "kraken",
          "pair": "ethjpy",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/kraken/ethjpy"
        },
        {
          "id": 120,
          "exchange": "kraken",
          "pair": "repjpy",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/kraken/repjpy"
        },
        {
          "id": 126,
          "exchange": "kraken",
          "pair": "zecjpy",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/kraken/zecjpy"
        },
        {
          "id": 140,
          "exchange": "kraken",
          "pair": "xrpjpy",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/kraken/xrpjpy"
        },
        {
          "id": 184,
          "exchange": "quoine",
          "pair": "btcjpy",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/quoine/btcjpy"
        },
        {
          "id": 196,
          "exchange": "quoine",
          "pair": "ethjpy",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/quoine/ethjpy"
        },
        {
          "id": 206,
          "exchange": "quoine",
          "pair": "bchjpy",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/quoine/bchjpy"
        },
        {
          "id": 215,
          "exchange": "bitflyer",
          "pair": "btcjpy",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/bitflyer/btcjpy"
        },
        {
          "id": 217,
          "exchange": "bitflyer",
          "pair": "btcjpy-weekly-futures",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/bitflyer/btcjpy-weekly-futures"
        },
        {
          "id": 218,
          "exchange": "bitflyer",
          "pair": "btcjpy-biweekly-futures",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/bitflyer/btcjpy-biweekly-futures"
        },
        {
          "id": 409,
          "exchange": "bitflyer",
          "pair": "btcfxjpy",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/bitflyer/btcfxjpy"
        },
        {
          "id": 248,
          "exchange": "bitmex",
          "pair": "btcjpy-quarterly-futures",
          "active": true,
          "route": "https://api.cryptowat.ch/markets/bitmex/btcjpy-quarterly-futures"
        },
        {
          "id": 424,
          "exchange": "bitmex",
          "pair": "btcjpy-monthly-futures",
          "active": false,
          "route": "https://api.cryptowat.ch/markets/bitmex/btcjpy-monthly-futures"
        }
      ]
    }
  },
  "allowance": {
    "cost": 162263,
    "remaining": 7999837737
  }
}

これを見ると個別のチャートを参照できるURLは


https://api.cryptowat.ch/markets/(取引所)/(通貨ペア)

であることがわかります。

他にもたくさんのデータが取得できるようです。

さあ、みんなもやってみよう。

 

👉 Kotlin 今どきよくある JSON リクエストからのパース hatena-bookmark


イベントハンドラとラムダ

おさらい


val printHelloWorld = {
   println("Hello, world!")
}

printHelloWorld()
//printHelloWorld.invoke()

これで以下が出力される。

Hello, world!

同様に引数を渡す。


val printGreeting = { word: String, name: String ->
   println("$word, $name")
}

printGreeting("おはよう", "太郎")
printGreeting.invoke("こんにちは", "次郎")

おはよう, 太郎
こんにちは, 次郎

これまでのコールバック

inferface を使ったコールバックは kotlin では以下のように書けます。


interface CallBackListener {
    fun onHoge(foo: String, bar: Int)
}

// caller
var callback: CallBackListener? = null
callback?.onHoge("foo", 100)

// callee
val callback = object : CallBackListener {
    override fun onHoge(foo: String, bar: Int) {
        print("$foo : $bar")
    }
}

これを typealias で。


typealias CallBackListener = (foo: String, bar: Int) -> Unit

// caller
var callback: CallBackListener? = null
callback?.invoke("foo", 100)

// callee
val callback = { foo, bar ->
    print("$foo : $bar")
}

【Kotlin】 TypeAliasで関数リテラルに名前を付ける - Qiita

イベントハンドラ

例えば、RecyclerView でそれぞれのアイテムのViewHolder内のある要素のクリックイベントを拾いたい時、Activity(View)までが遠いですよね。

Activity(View)
↓↑
RecyclerViewAdapter
↓↑
ViewHolder

少しでも、コールバック記述をシンプルにして見通し良くしておきたいものです。

ここで Type Alias を使います。

typealias EventHandler = (T) -> Unit

java - Kotlin: Use a lambda in place of a functional interface? - Stack Overflow

1. ViewHolder にハンドラー記述。クラスの外。

ItemViewHolder:


internal typealias ItemHandler = (Item) -> Unit

それを拡張して、ハンドラークラスを作ります。
invoke を override します。

ShareItemHandler:


internal class ShareItemHandler(
  private val activity: Activity
) : ItemHandler {

  override fun invoke(item: Item) {
    IntentBuilder.from(activity)
        .setType("text/plain")
        .setChooserTitle("Share ${item.name} to ?")
        .setText("${$item.name} ${item.address}")
        .startChooser()
  }
}

ClipboardCopyItemHandler:


internal class ClipboardCopyItemHandler(
  private val context: Context
) : ItemHandler {

  override fun invoke(item: Item) {
    val clipboard = context.systemService<ClipboardManager>()
    clipboard.primaryClip = ClipData.newPlainText(item.name, item.address)
  }
}

2. Activity で そのインスタンスを生成して
RecyclerAdapter経由でViewHolder内にセットしていきます。

以下関係部分のみ抜粋。

MainActivity:


val onCopy = ClipboardCopyItemHandler(this)
val onShare = ShareItemHandler(this)

// ...

val layoutManager = LinearLayoutManager(this)
recyclerView.layoutManager = layoutManager
val adapter = ItemAdapter(layoutInflater, onCopy, onShare)
recyclerView.adapter = adapter

ItemAdapter:


internal class ItemAdapter(
  private val inflater: LayoutInflater,
  private val onCopy: (Item) -> Unit,
  private val onShare: (Item) -> Unit
) : RecyclerView.Adapter<ItemViewHolder>() {

  // ...

  override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
    val view = inflater.inflate(R.layout.item, parent, false)
      return ItemViewHolder(view, onCopy, onShare)
    }

ItemViewHolder:



internal typealias ItemHandler = (Item) -> Unit // ***

internal class ItemViewHolder(
  private val root: View,
  private val onCopy: ItemHandler
  private val onShare: ItemHandler,
) : ViewHolder(root), OnClickListener, OnMenuItemClickListener {

  // ...  

  override fun onClick(view: View) = when(view.id) {
    R.id.copy -> onCopy(item!!)
    R.id.share -> onShare(item!!)
    else -> throw IllegalArgumentException("Unknown menu item: $menuItem")
  }

なんだか素晴らしいですね。

RecyclerView利用時のテンプレートとして。


あの Jake Wharton さんが伝授する Android Studio を高速化する方法

直接は関係ないような気がしますが

「Kotlinを使ったら Android Studio が遅くなった」

という疑問に対して、神と呼ばれる Jake Wharton さんがコメントしています。

「プラグイン捨てれ」

I find the IDE slower when adding any plugin. Especially ones which provide a great deal of functionality such as an entire language support.

Go to preferences > plugins > and disable everything you don't need. I disabled

Android APK Support
Android Games
Android NDK
App Links Assistant
CVS
EditorConfig
Firebase (all of them)
GitHub
Google (all of them)
hg4idea
Settings repository
Subversion integration
Task management
Terminal
Test recorder
TestNG
YAML

Goes real fast now.

JakeWharton comments on Android Studio slower when using Kotlin

本体や各ウインドウの起動などかなり高速化されます。

Kotlin や Google や RxJava など多岐に渡るオープンソースプロジェクトに深く関わる Jake さんが必要ないプラグインが私たち小市民に必要なわけがありません。

一回も使ったことがないプラグインが多くあるのは間違いありません。

他の多機能アプリやソフトウェアにも同様のことがいえます。

確認してみてはいかがでしょうか。