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 )