package Zaif; #UPDATE 2017/01/17 # #コンストラクタ # $api = Zaif->new( # # 'NONCE' => NONCE, # 'KEY' => API_KEY, # 'SECRET' => SECRET_KEY # ); # #※以下、いずれのメソッドも失敗時はエラー終了(die)します。 #プライベートAPI # # $api->getinfo(); # # $api->getinfo2(); # # $api->history('order' => 'ASC', 'currency_pair' => 'mona_jpy'); # # $api->activeorders('currency_pair' => 'mona_jpy'); # # $api->order( # # 'nonce' => time, #各メソッドにはパラメータでnonce値を指定可能 # 'currency_pair' => 'mona_jpy, # 'action' => 'bid', # 'price' => '9.2', # 'amount' => '2174', # ); # # $api->cancel('order_id' => '31415926'); # # 各APIメソッドの戻り値はreturnブロック内のデータが返されます。 # # #パブリックAPI (インスタンスからの呼び出しも可) # # Zaif->last_price('mona_jpy'); # # Zaif->ticker('btc_jpy'); # # Zaif->market_history('mona_jpy'); # # Zaif->depth('mona_btc'); # #nonce値の取得・設定 # $last_nonce = $api->nonce(); # $api->nonce( $new_nonce ); # # パラメータ: # $api->{'JSON'} # 解析前JSONデータ # no utf8; use strict "vars"; use Digest::SHA qw(hmac_sha512_hex); use HTTP::Request::Common; use LWP::UserAgent; use JSON qw(decode_json); use Encode qw(encode_utf8); use Scalar::Util qw(blessed); our $PUBLIC_URL = 'https://api.zaif.jp/api/1/'; our $PRIVATE_URL = 'https://api.zaif.jp/tapi'; our $USER_AGENT = 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:24.0) Gecko/20100101 Firefox/24.0'; our %PRICE_FORMAT = ( 'btc_jpy' => { 'price' => '%d', 'amount' => '%.4f'}, 'mona_jpy' => { 'price' => '%.1f', 'amount' => '%d'}, 'mona_btc' => { 'price' => '%.8f', 'amount' => '%d'}, 'xem_jpy' => { 'price' => '%.4f', 'amount' => '%.1f'} ); sub new{ my ($s,$c,$i,$v); $c = shift(@_); $s = {}; for($i = 0; $i < scalar(@_) - 1; $i += 2){ $a = $_[$i]; if($a eq 'KEY'){ $$s{'KEY'} = $_[$i + 1]; }elsif($a eq 'SECRET'){ $$s{'SECRET'} = $_[$i + 1]; }elsif($a eq 'NONCE'){ $$s{'NONCE'} = 0 + $_[$i + 1]; } } if(!defined($$s{'KEY'}) || !defined($$s{'SECRET'})){ $$s{'KEY'} = $$s{'SECRET'} = undef; } bless($s,$c); return $s; } # PRIVATE API methods. sub getinfo{ return _P(\@_,'get_info',[],[],{},undef); } sub getinfo2{ return _P(\@_,'get_info2',[],[],{},undef); } sub history{ return _P(\@_,'trade_history',['from','count','from_id','end_id','order','since','end','currency_pair'],[],{},undef); } sub activeorders{ return _P(\@_,'active_orders',['currency_pair'],[],{},undef); } sub order{ return _P(\@_,'trade',['currency_pair','action','price','amount','limit'],['currency_pair','action','price','amount'],{},\&_O); } sub cancel{ return _P(\@_,'cancel_order',['order_id'],['order_id'],{},undef); } #PUBLIC API methods. sub last_price{ return _G(\@_,'last_price'); } sub ticker{ return _G(\@_,'ticker'); } sub market_history{ return _G(\@_,'trades'); } sub nonce{ my($T); $T = shift(@_); if(!defined(blessed($T))){ return; } if(scalar(@_) > 0){ $$T{'NONCE'} = 0 + shift(@_); } return $$T{'_N'}; } #=========== PRIVATE FUNCTION ========= sub _P{ my($L,$T,$R,$S,@V,$a,$b,$h,$j,$s,%q); @V = @{$_[0]}; $T = shift(@V); if(!defined(blessed($T))){ return; }elsif(!defined($T->{'KEY'})){ die 'Undefined API KEY.'; return; } %q = ('method' => $V[1]); for($a = 0;$a < scalar(@V) - 1;$a += 2){ if($V[$a] eq 'method'){ }elsif($V[$a] eq 'nonce'){ $T->{'NONCE'} = 0 + $V[$a + 1] }else{ $b = $V[$a]; $q{defined($_[4]{$b}) ? $_[4]{$b} : $b} = $V[$a + 1]; } } #Mandatory foreach $s (@{$_[3]}){ if(!defined($q{$s})){ die 'Mandatory parameter \''.$s.'\' is undefined.'; return; } } if(ref($_[5]) eq 'CODE'){ if(!$_[5]->($T,\%q)){ return; } } if(!defined($T->{'NONCE'})){ $T->{'NONCE'} = time; } $T->{'_N'} = $T->{'NONCE'}; #Build query $s = 'nonce='.$T->{'NONCE'}.'&method='._E($_[1]); for($a = 0;$a < scalar(@{$_[2]});++$a){ $b = $_[2]->[$a]; if(defined($q{$b})){ $s .= '&'._E($b).'='._E($q{$b}); } } $h = hmac_sha512_hex($s,$$T{'SECRET'}); #POST $L = LWP::UserAgent->new; $L->timeout(10); $R = HTTP::Request->new('POST' => $PRIVATE_URL); $R->header('Key' => $$T{'KEY'}, 'Sign' => $h); $R->user_agent($USER_AGENT); $R->content_length(length($s)); $R->content_type('application/x-www-form-urlencoded'); $R->content($s); $S = $L->request($R); if(!$S->is_success){ die $S->status_line; return; } $$T{'NONCE'} += 1; eval{ $j = decode_json($S->content); }; if($@ || ref($j) ne 'HASH'){ die 'JSON parse error.'; return; } if(!$$j{'success'}){ die defined($$j{'error'}) ? $$j{'error'} : 'Unknown.'; return; } $$T{'JSON'} = $S->content; return $$j{'return'}; } sub _G{ my($T,$L,$R,$S,$j,@V); @V = @{$_[0]}; $T = shift(@V); $L = LWP::UserAgent->new; $L->timeout(10); $R = HTTP::Request->new('GET' => $PUBLIC_URL.$_[1].'/'._E($V[0])); $R->user_agent($USER_AGENT); $S = $L->request($R); if(!$S->is_success){ die 'HTTP Request error: '.$S->status_line; return; } eval{ $j = decode_json(encode_utf8($S->content)); }; if($@ || !ref($j)){ die 'JSON parse error.'; return; } return $j; } sub _O{ my($c,$d,$v); $v = $_[1]; $c = $$v{'currency_pair'}; $d = $PRICE_FORMAT{$c}; if(!defined($d)){ die "Invalid 'currency_pair'."; return; } if(defined($$d{'price'}) && _N($$v{'price'})){ $$v{'price'} = sprintf($$d{'price'},$$v{'price'}); } if(defined($$d{'amount'}) && _N($$v{'amount'})){ $$v{'amount'} = sprintf($$d{'amount'},$$v{'amount'}); } return 1; } #urlエンコード sub _E{ my($v); $v = $_[0]; $v =~ s/([^ 0-9A-Za-z\._\-])/'%'.unpack("H2",$1)/ge; $v =~ s/ /\+/g; return $v; } sub _N{ return ($_[0] ^ $_[0]) eq '0'; } 1; __END__ =encoding utf8 =head1 NAME Zaif - Using Zaif API module. =head1 SYNPOSIS =head2 CONSTRUCTOR use Zaif; $api = Zaif->new( 'KEY' => API_KEY , 'SECRET' => SECRET_KEY ); =head2 PRIVATE API METHODS #Return of response data. $api->getinfo(); $api->getinfo2(); $api->history( 'order' => 'ASC', 'currency_pair' => 'mona_jpy', 'limit' => 10 ); $api->activeorders('currency_pair' => 'mona_jpy'); $api->order( # 'nonce' => time, # You can set 'nonce' value for all PRIVATE API methods. 'currency_pair' => 'mona_jpy', 'action' => 'bid', 'price' => 9.2, 'amount' => 2174, ); $api->cancel('order_id' => '31415926'); =head2 PUBLIC API METHODS # Failed to die process. Zaif->last_price('mona_jpy'); Zaif->ticker('btc_jpy'); Zaif->market_history('mona_jpy'); Zaif->depth('mona_btc'); $api = Zaif->new(); $api->market_history('mona_jpy'); =head2 OTHER METHODS $last_nonce = $api->nonce(); $api->nonce( $new_nonce ); =cut