Clearing more bugs, code included

Hi Guys,

Script was running for another 24hours and it looks like it is hung. Nevertheless it made some profits!

Here’s an updated code that hopefully clear all identified bugs:


<?php

require( 'CoinbaseExchangeRequest.php' );
require( 'CoinbaseExchange.php' );
require __DIR__ . '/vendor/autoload.php';

$percentage = 0.001; // 0.1%

$lastPrice = array(); 
$lastPriceTime = array(); 
$lastPrice[ 'BTC-EUR' ] = 0;
$lastPrice[ 'ETH-EUR' ] = 0;
$lastPrice[ 'LTC-EUR' ] = 0;
$lastPrice[ 'BCH-EUR' ] = 0;
$lastPrice[ 'ETH-BTC' ] = 0;
$lastPrice[ 'LTC-BTC' ] = 0;
$lastPrice[ 'BCH-BTC' ] = 0;

$exchange = new CoinbaseExchange();
$exchange->auth( '***', ''***', ''***');

$loop = React\EventLoop\Factory::create();
$reactConnector = new React\Socket\Connector($loop, [
    'dns' => '8.8.8.8',
    'timeout' => 10
]);
$connector = new Ratchet\Client\Connector($loop, $reactConnector);

$connector('wss://ws-feed.gdax.com')->then(function($conn) {
    $conn->on('close', function($code = null, $reason = null) {
        echo "\nConnection closed ({$code} - {$reason})\n";
    });

    $conn->on('message', function($msg) use ($conn) {
        global $exchange, $lastPrice, $percentage, $lastPriceTime;
        $data = json_decode($msg,1);

        if( $data[ 'type' ] == 'match' ) {
            if( in_array( $data[ 'product_id' ], array( 'BTC-EUR', 'ETH-BTC', 'LTC-BTC', 'ETH-EUR', 'LTC-EUR', 'BCH-EUR', 'BCH-BTC' )  ) ) {
                $pair1 = substr( $data[ 'product_id' ], 0, 3 );
                $pair2 = substr( $data[ 'product_id' ], 4, 6 );

                $openOrders = $exchange->listOrders();
                $countOpenOrders = 0;
                $uniquePairs = array();
                $now = new DateTime('now');
                if( $openOrders ) {
                    foreach( $openOrders as $order ) {
                        $createdAt = new DateTime( $order[ 'created_at' ] );
                        $diff = $now->diff( $createdAt );
                        $diff = $diff->format("%h");
    
                        /**
                         * let's cancell orders older than 8= hours (time at exchange is -2h compared to local time)
                         */
                        if( $diff > 5 ) {
                            $exchange->cancelOrder( $order[ 'id' ] );
                            $lastPrice[ $order[ 'product_id' ] ] = 0;
                            echo "\nKilling orders for pair ".$order[ 'product_id' ].', time='.date('Y-m-d H:i:s');
                            continue;
                        }
    
                        $uniquePairs[ $order[ 'product_id' ] ] = 1;
                        if( $order[ 'product_id' ] == $data[ 'product_id' ] ) {
                            $countOpenOrders++;
                        }
                    }
                }

                if( $countOpenOrders > 1 ) { // let's not have more than 2 open transactions per 1 pair
                    return;
                }

                $countUniquePairs = 0;
                foreach( $uniquePairs as $uniquePair ) {
                    if( $uniquePair ) {
                        $countUniquePairs++;
                    }
                }
                
                $balanceBTCAvailable = $exchange->getAccount( ''***' )[ 'available' ];
                $balanceEURAvailable = $exchange->getAccount( ''***' )[ 'available' ];
                $balanceBCHAvailable = $exchange->getAccount( ''***' )[ 'available' ];
                $balanceETHAvailable = $exchange->getAccount( ''***' )[ 'available' ];
                $balanceLTCAvailable = $exchange->getAccount( ''***' )[ 'available' ];
                $balanceETCAvailable = $exchange->getAccount( ''***' )[ 'available' ];

                /**
                 * @TODO catch exceptions from exchange on getAccount method. happens sometimes
                 */

                $balancePair1Available = 'balance'.$pair1.'Available';
                $balancePair2Available = 'balance'.$pair2.'Available';

                /**
                 * restart lastPrice per pair every 8 hours
                 */
                if( isset( $lastPriceTime[ $data[ 'product_id' ] ] ) )  {
                    $now = new DateTime('now'); 
                    $diff = $now->diff( $lastPriceTime[ $data[ 'product_id' ] ] );

                    if( $diff ) {
                        $diff = $diff->format("%h");    
                    }                        

                    if( $diff > 7 ) {
                        $lastPriceTime[ $data[ 'product_id' ] ] = new DateTime( 'now' );
                        $lastPrice[ $data[ 'product_id' ] ] = 0;
                    }
                }
                
                /**
                 * selling
                 */
                if( $data[ 'price' ] > (1 + $percentage) * $lastPrice[ $data[ 'product_id' ] ] && $$balancePair1Available > 0 ) { 
                    $book = $exchange->getOrderBook( $data[ 'product_id' ] );

                    if( !$book || !isset( $book[ 'bids' ] ) ) {
                        return;
                    }

                    $maxBid = $book[ 'bids' ][ 0 ][ 0 ];
                    
                    if( $pair2 == 'EUR' ) {
                        $price = round( max( $maxBid + 0.01, $data[ 'price' ] ), 2 );
                    } else { // BTC
                        $price = round( max( $maxBid + 0.00001, $data[ 'price' ] ), 6 );
                    }
                    
                    $size = $$balancePair1Available;
                
                    if( $pair1 == 'BTC' && $size < 0.001 || 
                        $pair1 == 'LTC' && $size < 0.1 ||
                        $pair1 == 'ETC' && $size < 0.1 ||
                        $pair1 == 'ETH' && $size < 0.01 || 
                        $pair1 == 'BCH' && $size < 0.01) {
                            
                        return;
                    }

                    if( $pair1 == 'BTC' ) {
                        $size = round( $size * 10, 7 ) / 10; // just rounding may be inaccurate. kind of floor operation..
                    }

                    echo "\n$data[product_id], Selling $size $pair1 at price $price $pair2, time=".date('Y-m-d H:i:s');
                    
                    $sell = $exchange->placeOrder('sell', $price, $size, $data[ 'product_id' ]); 

                    if( isset( $sell[ 'id' ] ) ) {
                        $lastPrice[ $data[ 'product_id' ] ] = $price;
                        $lastPriceTime[ $data[ 'product_id' ] ] = new DateTime( 'now' );
                    }
                    print_r( $sell );
                }
                /**
                 * buying
                 */
                if( ( !$lastPrice[ $data[ 'product_id' ] ] || $data[ 'price' ] <= $lastPrice[ $data[ 'product_id' ] ] ) ) { 
                    $book = $exchange->getOrderBook( $data[ 'product_id' ] );
                    $minAsk = $book[ 'asks' ][ 0 ][ 0 ];
                
                    if( $pair2 == 'EUR' ) {
                        $price = round( min( $minAsk - 0.01, $data[ 'price' ] ), 2 );
                    } else { // BTC
                        $price = round( min( $minAsk - 0.00001, $data[ 'price' ] ), 6 );
                    }
                    
                    /**
                     * @TODO poprawic na pair2
                     */
                    $size = round( 0.99*$$balancePair2Available / $price / ( max( 1, 6 - $countUniquePairs ) ), 7 ); 
                
                    if( $pair1 == 'BTC' && $size < 0.001 || 
                        $pair1 == 'LTC' && $size < 0.1 ||
                        $pair1 == 'ETC' && $size < 0.1 ||
                        $pair1 == 'ETH' && $size < 0.01 || 
                        $pair1 == 'BCH' && $size < 0.01) {

                        return;
                    }
                
                    echo "\n$data[product_id], Buying $size $pair1 at price $price $pair2, time=".date('Y-m-d H:i:s');
                    
                    $buy = $exchange->placeOrder('buy', $price, $size, $data[ 'product_id' ] ); 

                    if( isset( $buy[ 'id' ] ) ) {
                        $lastPrice[ $data[ 'product_id' ] ] = $price;
                        $lastPriceTime[ $data[ 'product_id' ] ] = new DateTime( 'now' );
                    }

                    print_r( $buy );
                }
            }
        }
    });

    /**
     * websocket connection to Coinbase Pro to fetch real-time trades (matches)
     */
    $conn->send( '{ "type" : "subscribe", 
                    "product_ids" : [ "BTC-EUR", "ETH-BTC", "LTC-BTC", "ETH-EUR", "LTC-EUR", "BCH-EUR", "BCH-BTC" ],
                    "channels" : [ "matches" ],
                    "secret": "'***",
                    "key": "'***",
                    "passphrase": "'***"}' );
}, function ($e) {
    echo "Could not connect: {$e->getMessage()}\n";
});


$loop->run();
?>

Thanks for reading,
Łukasz.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s