ビットバンク(bitbank)で逆指値注文ができるようになりましたね。
自分の場合bitbankは長期投資のガチ保用で使っていましたが、これを機会にアクティブに使ってみようかと思い、iPhoneで損益を見るアプリを作ろうかと考え中です。
試しにbitbankのAPIをお試しで使ってみようとしたところ、Pythonやnode.jsの公式ライブラリは公開されているのですが、iOS版は存在しません。自前でREST APIの呼び出しを実装する必要がありまが、最初の認証がなんとも厄介で、かなりハマったのでその時のメモです。
認証に失敗すると 20001 が返ってくるのですが、理由を示す情報が含まれていないため試行錯誤するしかありません。
エラーレスポンスの例
{
"data" : { "code" : 20001 },
"success" : 0
}
認証のポイント
- UNIXタイムスタンプ(timeIntervalSince1970)をそのままIntに変換すると、少数部が丸められインクリメントされないため、連続で呼び出すと認証に失敗する。1000とか10000倍してからIntに変換することで回避できる。
- 署名に指定するクエリパラメータは ? を付ける
- クエリのパスは /v1 で始める
- bitbankで取得したAPIシークレットキーを使って、HMAC-SHA256 形式で署名する
約定履歴の認証の例
swift
let privateEndpoint = "https://api.bitbank.cc"
let path = "/v1/user/spot/trade_history"
let queryParam = "?pair=btc_jpy"
let urlString = privateEndpoint + path + queryParam
let url = URL(string: urlString)!
var request = URLRequest(url: url)
let date: Date = Date()
let nonce = String(Int(date.timeIntervalSince1970 * 10000))
let signature = makeSignature(secret: apiSecret, nonce: nonce, path: path, queryParam: queryParam)
サンプル全文
GETリクエストは標準APIを使用しています。
HMAC-SHA256の署名方法は@kohei1218さんの記事を参考にさせていただきました。
swift
import UIKit
import CryptoSwift
class ViewController: UIViewController {
let publicEndpoint = "https://public.bitbank.cc"
let privateEndpoint = "https://api.bitbank.cc"
let apiKey = "bitbankのポータルサイトで取得したAPIキー"
let apiSecret = "bitbankのポータルサイトで取得したシークレット"
override func viewDidLoad() {
super.viewDidLoad()
getPrivateTradeHistory()
}
func getPrivateTradeHistory() {
let path = "/v1/user/spot/trade_history"
let queryParam = "?pair=btc_jpy"
let urlString = privateEndpoint + path + queryParam
let url = URL(string: urlString)!
var request = URLRequest(url: url)
let date: Date = Date()
let nonce = String(Int(date.timeIntervalSince1970 * 10000))
let signature = makeSignature(secret: apiSecret, nonce: nonce, path: path, queryParam: queryParam)
request.httpMethod = "GET"
request.allHTTPHeaderFields = ["ACCESS-KEY": apiKey]
request.allHTTPHeaderFields = ["ACCESS-NONCE": nonce]
request.allHTTPHeaderFields = ["ACCESS-SIGNATURE": signature]
let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data else { return }
do {
let object = try JSONSerialization.jsonObject(with: data, options: [])
print(object)
} catch let error {
print(error)
}
}
task.resume()
}
func makeSignature(secret: String, nonce: String, path: String, queryParam: String = "") -> String {
let str = nonce + path + queryParam
print(str)
let bytes = str.bytes
var signature = ""
do {
let hmac = try HMAC(key: secret, variant: .sha256).authenticate(bytes)
signature = hmac.toHexString()
} catch let error {
print(error)
}
return signature
}
}
extension StringProtocol {
var bytes: [UInt8] { .init(utf8) }
}