こんにちは。くろしばです。
多くの仮想通貨取引所が取引のレートや、実際に注文をすることができる機能を持たせたAPIを公開しています。
その中でもpoloniexの取引所は単にURLを公開していると言うよりは、プログラムを公開して、これを使ってね。
みたいなスタンス。
そのpoloniexのAPIを呼び出すプログラムを実装してみました!
スポンサーリンク
まずはAPIキーを発行する
他の取引所では必要なかったのですが、poloniexではpublic APIを呼び出すのにもAPIキーが必要みたいです。
ちなみにここでは
public API : ログインの必要がない情報を取得するAPI(各通貨の価格など)
認証API : 本来ログイン後にのみ使用することができる機能(通貨の売買など)
てな感じで表現していきます(-∀-)!
APIキーの発行はそんなに難しくありません。
poloniexにアクセスし、右上のスパナマークをクリックすると、
ペロンとメニューがでてきます。
ここの「API KEYS」を選択します。
送信されたメールのURLにアクセスすればAPIキーの発行が完了します!
ここで注意なのはとりあえずAPI叩いてみたいよってレベルの人は必ず
「Enable Withdraws」にチェックをしないでください!
シークレットキーを発行
先ほどのキー発行画面のAPIキーの下にシークレットキーを表示するボタンがあるのでそこから確認することができます。
このキーの扱いには十分注意してくださいね!
普段お金を送金させたりするときは、
poloniexにログインして、
多くの人が2段階認証の認証を行い、
画面を操作し、確認を行いながら
送金を行うかと思いますが、APIというのはURLリクエスト1つでサクッと送金ができてしまう道具です。
え?ログインもなしに?
と思った方もいるかと思いますが、そのログイン作業の代わりがシークレットキーというわけです。
逆に言えばシークレットキーが人にバレてしまうと、ログインして好きな操作していいよ!
と言っているようなものなのです。
前述ではありますが、それを防止するためにも「Enable Withdraws」にチェックをつけなければAPIから引き出しは行えないはずです。
ラッパークラスを引っ張ってくる
下記のページからそれぞれ
PHP wrapper
Python wrapper
をコピーしてきます。
今回はサクッと作りたかったのでいつも使っているPHPを使いました。
ディレクトリ構成はこんな感じ。
├── coin │ ├── poloniex │ │ ├── getPoloniexData.php │ │ └── poloniex.php │ ├── shell │ │ └── getPoloniexData.sh │ └── util │ └── util.php └── mail └── mail.php
環境は
OS : macOS High Sierra
PHP : 7.1.7
とりあえず呼び出してみた
各ファイルの中身はこんな感じです。
ラッパークラスは多少クラス名を変えたりしたので一応載っけときます。
・poloniex.php(ラッパークラス)
<?php // FINAL TESTED CODE - Created by Compcentral // NOTE: currency pairs are reverse of what most exchanges use... // For instance, instead of XPM_BTC, use BTC_XPM class Poloniex { protected $api_key; protected $api_secret; protected $trading_url = "https://poloniex.com/tradingApi"; protected $public_url = "https://poloniex.com/public"; public function __construct($api_key, $api_secret) { $this->api_key = $api_key; $this->api_secret = $api_secret; } private function query(array $req = array()) { // API settings $key = $this->api_key; $secret = $this->api_secret; // generate a nonce to avoid problems with 32bit systems $mt = explode(' ', microtime()); $req['nonce'] = $mt[1].substr($mt[0], 2, 6); // generate the POST data string $post_data = http_build_query($req, '', '&'); $sign = hash_hmac('sha512', $post_data, $secret); // generate the extra headers $headers = array( 'Key: '.$key, 'Sign: '.$sign, ); // curl handle (initialize if required) static $ch = null; if (is_null($ch)) { $ch = curl_init(); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; Poloniex PHP bot; '.php_uname('a').'; PHP/'.phpversion().')' ); } curl_setopt($ch, CURLOPT_URL, $this->trading_url); curl_setopt($ch, CURLOPT_POSTFIELDS, $post_data); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); // run the query $res = curl_exec($ch); if ($res === false) throw new Exception('Curl error: '.curl_error($ch)); //echo $res; $dec = json_decode($res, true); if (!$dec){ //throw new Exception('Invalid data: '.$res); return false; }else{ return $dec; } } protected function retrieveJSON($URL) { $opts = array('http' => array( 'method' => 'GET', 'timeout' => 10 ) ); $context = stream_context_create($opts); $feed = file_get_contents($URL, false, $context); $json = json_decode($feed, true); return $json; } public function get_balances() { return $this->query( array( 'command' => 'returnBalances' ) ); } public function get_open_orders($pair) { return $this->query( array( 'command' => 'returnOpenOrders', 'currencyPair' => strtoupper($pair) ) ); } public function get_my_trade_history($pair) { return $this->query( array( 'command' => 'returnTradeHistory', 'currencyPair' => strtoupper($pair) ) ); } public function buy($pair, $rate, $amount) { return $this->query( array( 'command' => 'buy', 'currencyPair' => strtoupper($pair), 'rate' => $rate, 'amount' => $amount ) ); } public function sell($pair, $rate, $amount) { return $this->query( array( 'command' => 'sell', 'currencyPair' => strtoupper($pair), 'rate' => $rate, 'amount' => $amount ) ); } public function cancel_order($pair, $order_number) { return $this->query( array( 'command' => 'cancelOrder', 'currencyPair' => strtoupper($pair), 'orderNumber' => $order_number ) ); } public function withdraw($currency, $amount, $address) { return $this->query( array( 'command' => 'withdraw', 'currency' => strtoupper($currency), 'amount' => $amount, 'address' => $address ) ); } public function get_trade_history($pair) { $trades = $this->retrieveJSON($this->public_url.'?command=returnTradeHistory¤cyPair='.strtoupper($pair)); return $trades; } public function get_order_book($pair) { $orders = $this->retrieveJSON($this->public_url.'?command=returnOrderBook¤cyPair='.strtoupper($pair)); return $orders; } public function get_volume() { $volume = $this->retrieveJSON($this->public_url.'?command=return24hVolume'); return $volume; } public function get_ticker($pair = "ALL") { $pair = strtoupper($pair); $prices = $this->retrieveJSON($this->public_url.'?command=returnTicker'); if($pair == "ALL"){ return $prices; }else{ $pair = strtoupper($pair); if(isset($prices[$pair])){ return $prices[$pair]; }else{ return array(); } } } public function get_trading_pairs() { $tickers = $this->retrieveJSON($this->public_url.'?command=returnTicker'); return array_keys($tickers); } public function get_total_btc_balance() { $balances = $this->get_balances(); $prices = $this->get_ticker(); $tot_btc = 0; foreach($balances as $coin => $amount){ $pair = "BTC_".strtoupper($coin); // convert coin balances to btc value if($amount > 0){ if($coin != "BTC"){ $tot_btc += $amount * $prices[$pair]; }else{ $tot_btc += $amount; } } // process open orders as well if($coin != "BTC"){ $open_orders = $this->get_open_orders($pair); foreach($open_orders as $order){ if($order['type'] == 'buy'){ $tot_btc += $order['total']; }elseif($order['type'] == 'sell'){ $tot_btc += $order['amount'] * $prices[$pair]; } } } } return $tot_btc; } } ?>
・getPoloniexData.php
<?php require_once realpath(dirname(__FILE__)) . '/poloniex.php'; require_once realpath(dirname(__FILE__)) . '/../util/util.php'; require_once realpath(dirname(__FILE__)) . '/../../mail/mail.php'; class GetPoloniexData extends Poloniex { private $mailFlag; /** * コンストラクタ */ public function __construct($argv) { $keys = Util::pickUpKeys($argv); $this->mailFlag = Util::isSendMail($argv); parent::__construct($keys['api'], $keys['sec']); } /** * メインロジック */ public function execute(){ try{ // ユーザ情報を含むAPIの利用 if(is_null($this->api_secret) === false){ // 使いたくなったら使う } // publicAPIの利用 if(is_null($this->api_key) === false){ $ticker = $this->get_ticker(); } if(is_null($ticker)){ throw new Exception('APIからのデータが取得なーい!!'); } if($this->mailFlag){ $this->_sendMail($ticker); } }catch(Exception $e){ echo "<エラーが発生しました!!!>\n\n"; echo $e->getMessage() . "\n\n"; exit(0); } } /** * メインロジック */ private function _sendMail($retJson){ $sendInfo = array(); $sendInfo['to'] = ''; // 実行前にメールアドレスを入力する。 $sendInfo['subject'] = 'poloniex info'; $sendInfo['message'] = $this->_getMailText($retJson); $mail = new Mail(); $mail->sendMail($sendInfo); } private function _getMailtext($retJson){ $t = ''; foreach($retJson as $key => $coinData){ $t .= "・" . $key . "\n"; $t .= " quotVolume : " . $coinData['quoteVolume']. "\n"; $t .= " vaseVolume : " . $coinData['baseVolume']. "\n"; $t .= "\n"; } return $t; } } $poloniexApi = new getPoloniexData($argv); $ret = $poloniexApi->execute(); exit(1);
・util.php
<?php class Util{ /** * APIkeyとsecret keyをオプションから取り出す処理 * 今の所、poloniexのリクエスト用に使用 * @return $key */ public static function pickUpKeys($argv){ $key = array(); foreach($argv as $option){ $tmp = explode('=', $option); $key[$tmp[0]] = $tmp[1]; } return $key; } public static function isSendMail($argv){ return in_array('--sendMail', $argv) ? true : false; } }
・mail.php
<?php class Mail{ public function sendMail($sendInfo){ $to = isset($sendInfo['to']) ? $sendInfo['to'] : null; $subject = isset($sendInfo['subject']) ? $sendInfo['subject'] : null; $message = isset($sendInfo['message']) ? $sendInfo['message'] : 'テスト送信です。'; $addHeaders = isset($sendInfo['addHeader']) ? $sendInfo['addHeader'] : null; $addParam = isset($sendInfo['addParam']) ? $sendInfo['addParam'] : null; echo $message; // メール送信が可能かチェックする $this->_canSendMail($to, $subject); if(mb_send_mail($to, $subject, $message, $addHeaders, $addParam) == false){ throw new Exception('メール送信失敗したー!!'); } } private function _canSendMail($to, $subject){ if($to == null){ throw new Exception('宛先がないよ'); } if($subject == null){ throw new Exception('題名がないよ'); } if(strpos(gethostname(), 'local')){ throw new Exception('ローカルは送らないでおくね。'); } } }
・getPoloniexData.sh
#!/bin/sh echo "<--call poloniex API-->\n" /usr/bin/php ../poloniex/getPoloniexData.php "$@" echo "<--end poloniex API-->\n"
.shファイルを実行することでphpでレートを取得する流れになっているので、
やることはgetPoloniexData.shを実行するだけです。
sh getPoloniexData.sh api=ここにAPIキーを入力
オプションで取得結果をメール送信させる処理も入れましたが、
ローカル環境では多分動かないので今回は使わないでいきます。
細かいところがまだ未完成ではありますが、とりあえずmacのどこかにおけば動くとは思います。
まとめ
正直Javaをしっかりとやったことがないのでラッパークラスといってもいまいちピンときませんでした。(´・д・`)
アクセス修飾子を見る限りpublicがあったりprotectedがあったり、
ライブラリ的に使えばいいのか、はたまた継承すればいいのか。。。
とりあえず後者で実装してみました。
このバッチ自体は雑に作っちゃいましたが、他の取引所のデータも取得したりして少しまともなwebページを公開できたらなと思っていますのでお待ちくださいませー!
ではでは( *`ω´)ノ
スポンサーリンク