App-cryp-arbit
view release on metacpan or search on metacpan
lib/App/cryp/arbit/Strategy/merge_order_book.pm view on Meta::CPAN
unless grep { $_ eq $quotecur } @{ $fiat_for{$exchange} };
} else {
$key = "$basecur/$quotecur";
}
$exchanges_for{$key} //= [];
push @{ $exchanges_for{$key} }, $exchange;
$pairs_for{$exchange} //= [];
push @{ $pairs_for{$exchange} }, $pair
unless grep { $_ eq $pair } @{ $pairs_for{$exchange} };
}
} # DETERMINE_SETS
SET:
for my $set (shuffle keys %exchanges_for) {
my ($base_currency, $quote_currency0) = $set =~ m!(.+)/(.+)!;
my %sell_orders; # key = exchange safename
my %buy_orders ; # key = exchange safename
# the final merged order book. each entry will be a hashref containing
# these keys:
#
# - currency (the base/target currency to arbitrage)
#
# - gross_price_orig (ask/bid price in exchange's original quote
# currency)
#
# - gross_price (like gross_price_orig, but price will be converted to
# USD if quote currency is fiat)
#
# - net_price_orig (net price after adding [if sell order, because we'll
# be buying these] or subtracting [if buy order, because we'll be
# selling these] trading fee from the original ask/bid price. in
# exchange's original quote currency)
#
# - net_price (like net_price_orig, but price will be converted to USD
# if quote currency is fiat)
#
# - exchange (exchange safename)
my @all_buy_orders;
my @all_sell_orders;
# produce final merged order book.
EXCHANGE:
for my $exchange (sort keys %{ $r->{_stash}{exchange_clients} }) {
my $eid = App::cryp::arbit::_get_exchange_id($r, $exchange);
my $clients = $r->{_stash}{exchange_clients}{$exchange};
my $client = $clients->{ (sort keys %$clients)[0] };
my @pairs;
if ($quote_currency0 eq ':fiat') {
push @pairs, map { "$base_currency/$_" } @{ $fiat_for{$exchange} };
} else {
push @pairs, $set;
}
PAIR:
for my $pair (@pairs) {
my ($basecur, $quotecur) = split m!/!, $pair;
next unless grep { $_ eq $pair } @{ $pairs_for{$exchange} };
my $time = time();
log_debug "Getting orderbook %s on %s ...", $pair, $exchange;
my $res = $client->get_order_book(pair => $pair);
unless ($res->[0] == 200) {
log_error "Couldn't get orderbook %s on %s: %s, skipping this pair",
$pair, $exchange, $res;
next PAIR;
}
#log_trace "orderbook %s on %s: %s", $pair, $exchange, $res->[2]; # too much info to log
# sanity checks
unless (@{ $res->[2]{sell} }) {
log_warn "No sell orders for %s on %s, skipping this pair",
$pair, $exchange;
next PAIR;
}
unless (@{ $res->[2]{buy} }) {
log_warn "No buy orders for %s on %s, skipping this pair",
$pair, $exchange;
last PAIR;
}
my $buy_fee_pct = App::cryp::arbit::_get_trading_fee(
$r, $exchange, $base_currency);
for (@{ $res->[2]{buy} }) {
push @{ $buy_orders{$exchange} }, {
quote_currency => $quotecur,
gross_price_orig => $_->[0],
net_price_orig => $_->[0]*(1-$buy_fee_pct/100),
base_size => $_->[1],
};
}
my $sell_fee_pct = App::cryp::arbit::_get_trading_fee(
$r, $exchange, $base_currency);
for (@{ $res->[2]{sell} }) {
push @{ $sell_orders{$exchange} }, {
quote_currency => $quotecur,
gross_price_orig => $_->[0],
net_price_orig => $_->[0]*(1+$sell_fee_pct/100),
base_size => $_->[1],
};
}
if (!App::cryp::arbit::_is_fiat($quotecur) || $quotecur eq 'USD') {
for (@{ $buy_orders{$exchange} }, @{ $sell_orders{$exchange} }) {
$_->{gross_price} = $_->{gross_price_orig};
$_->{net_price} = $_->{net_price_orig};
}
$dbh->do("INSERT INTO price (time,base_currency,quote_currency,price,exchange_id,type) VALUES (?,?,?,?,?,?)", {},
$time, $base_currency, $quotecur, $buy_orders{$exchange}[0]{gross_price_orig}, $eid, "buy");
$dbh->do("INSERT INTO price (time,base_currency,quote_currency,price,exchange_id,type) VALUES (?,?,?,?,?,?)", {},
$time, $base_currency, $quotecur, $sell_orders{$exchange}[0]{gross_price_orig}, $eid, "sell");
} else {
# convert fiat to USD
my $fxrate = $r->{_stash}{forex_rates}{"$quotecur/USD"}
or die "BUG: Didn't get forex rate for $quotecur/USD?";
( run in 0.567 second using v1.01-cache-2.11-cpan-f52f0507bed )