├── LICENSE ├── README.md ├── cryptopiaAPI.php ├── exchange.php ├── nicehashAPI.php └── nicehashbot.php /LICENSE: -------------------------------------------------------------------------------- 1 | LICENSE 2 | 3 | BipCot NoGov Software License (www.bipcot.org), version 1.12 / No warranty of 4 | usability of bipcoin-nicehash-bot software. 5 | 6 | This original computer code and resulting program was made by license holder 7 | KittyCatTech, 2017. All rights to make fun of you reserved. 8 | https://github.com/KittyCatTech/bipcoin-nicehash-bot 9 | 10 | Redistribution and use in source and binary forms, with or without modification, 11 | are permitted provided that the following conditions are met: 12 | 13 | 1. Redistributions and adaptations of source code or program must retain the 14 | entirety of this license, including retaining attribution of the license holder 15 | of the software. 16 | 17 | 2. Redistributions in binary form must reproduce the entirety of this license. 18 | 19 | 3. Neither the name of the license holder nor the names of its contributors may 20 | be used to endorse or promote products derived from this software without 21 | specific prior written permission. Furthermore, no attempt will be made to 22 | impersonate the person or entity whose software is being used or modified. 23 | 24 | 4. Governments, and agents and subcontractors of same, are not permitted to use 25 | this software or derivations of this software. 26 | 27 | 5. If governments, agents and subcontractors of same use this software, or 28 | derivations of this software, all agencies and persons directly and knowingly 29 | involved may be shamed in public, by name, on the Internet, on radio, and in any 30 | media now extant or invented in the future, throughout the known universe and 31 | elsewhere, in perpetuity. Governments, agents and subcontractors of same that 32 | use this software, or derivations of this software, agree to endure this 33 | shaming, without comment or action. 34 | 35 | 6. Any person or entity that violates any part of this agreement will also be 36 | shamed as above, and agrees to endure this shaming, without comment or action. 37 | 38 | 7. The BipCot NoGov Software License adopts the first 3 clauses of the 3-Clause 39 | BSD license (Berkeley Software Distribution license) and adopts the BSD "as is" 40 | text at the end. The 3-Clause BSD license is in the Public Domain. However, 41 | there is no partnership or endorsement created or implied between the creators 42 | or users of The BipCot NoGov Software License and the creators or users of the 43 | BSD license, or vise versa. 44 | 45 | 46 | THIS SOFTWARE IS PROVIDED BY THE LICENSE HOLDER AND CONTRIBUTORS "AS IS" AND ANY 47 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 48 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 49 | DISCLAIMED. IN NO EVENT SHALL THE LICENSE HOLDER OR CONTRIBUTORS BE LIABLE FOR 50 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 51 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 52 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 53 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 54 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 55 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # bipcoin-nicehash-bot 2 | [NiceHash](https://www.nicehash.com/?refby=88315) Order Updating bot for renting hashing power to mine BipCoin 3 | 4 | ###This Script Updates Orders on NiceHash based on: 5 | 6 | 1. Total Network Hashrate and block reward, from mining pool 7 | 2. Price of BIP on Cryptopia order book 8 | 3. Lowest cost to buy hashing on Nicehash order book 9 | 10 | ###Sign up for NiceHash with my affiliate link: 11 | https://www.nicehash.com/?refby=88315 12 | 13 | Deposit BTC to your account. Get your API Id and Key to put in [nicehashbot.php](https://github.com/KittyCatTech/bipcoin-nicehash-bot/blob/master/nicehashbot.php) script. 14 | 15 | ###Add mining pools: 16 | https://www.nicehash.com/index.jsp?p=managepools 17 | 18 | EU >> host: bip.ms-pool.net.ua port: 8888 username: \ password: x 19 | 20 | US >> host: pool.democats.org port: 45591 username: \ passoword: x 21 | 22 | ###Place Orders 23 | https://www.nicehash.com/index.jsp?p=orders 24 | 25 | Select CryptoNight Algorithm 26 | 27 | Add one standard order for EU hashing sever and one order for US hasing sever 28 | 29 | ###Automate 30 | Run script [nicehashbot.php](https://github.com/KittyCatTech/bipcoin-nicehash-bot/blob/master/nicehashbot.php) and schedule it to run every 10-15 Mins. 31 | 32 | ###License: 33 | 34 | [BipCot NoGov Software License](https://github.com/KittyCatTech/bipcoin-nicehash-bot/blob/master/LICENSE) 35 | 36 | ###Donations 37 | 38 | If you found this software useful please donate and let me know you appriciate my work on [twitter](http://twitter.com/KittyCatTech) or [reddit](https://www.reddit.com/user/KittyCatTech). 39 | 40 | Donations are accepted in Monero and BipCoin: 41 | 42 | XMR: 49kC7NB3iagZf2T4AhBdL84N9JaugEhvJVJDBEuMEKQSUnrx3xFoDzejpRKiSgX7V1j1im8h8xyRmNXJJSQtBtJS7F25nzs 43 | 44 | BIP: bip1WevdQxcaVYr1bRuqEsEqU4vEJ5qFtHsrWANG7hbTYyvTmvTswC8FcX6yAZ2MunWE3Fu1qLpTBVUnf7hDhWpi4BbozDmQJ1 45 | -------------------------------------------------------------------------------- /cryptopiaAPI.php: -------------------------------------------------------------------------------- 1 | privateKey = $priv; 8 | $this->publicKey = $pub; 9 | 10 | if ($priv) { // do not check connection for public API only with no Keys 11 | $result = json_decode($this->apiCall("GetBalance", array( 'Currency'=> 'BTC' )), true); 12 | // print_r($result); 13 | if( $result['Success'] != "true" ) { 14 | throw new Exception("Can't Connect to Cryptopia, Error: " . $result['Error'] ); 15 | return false; 16 | } 17 | return true; 18 | } 19 | } 20 | 21 | private function apiCall($method, array $req = array()) { 22 | $public_set = array( "GetCurrencies", "GetTradePairs", "GetMarkets", "GetMarket", "GetMarketHistory", "GetMarketOrders" ); 23 | $private_set = array( "GetBalance", "GetDepositAddress", "GetOpenOrders", "GetTradeHistory", "GetTransactions", "SubmitTrade", "CancelTrade", "SubmitTip" ); 24 | static $ch = null; 25 | $ch = curl_init(); 26 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 27 | //curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/4.0 (compatible; Cryptopia.co.nz API PHP client; FreeBSD; PHP/'.phpversion().')'); 28 | if ( in_array( $method ,$public_set ) ) { 29 | $url = "https://www.cryptopia.co.nz/api/" . $method; 30 | if ($req) { foreach ($req as $r ) { $url = $url . '/' . $r; } } 31 | curl_setopt($ch, CURLOPT_URL, $url ); 32 | } elseif ( in_array( $method, $private_set ) ) { 33 | $url = "https://www.cryptopia.co.nz/Api/" . $method; 34 | $nonce = explode(' ', microtime())[1]; 35 | $post_data = json_encode( $req ); 36 | $m = md5( $post_data, true ); 37 | $requestContentBase64String = base64_encode( $m ); 38 | $signature = $this->publicKey . "POST" . strtolower( urlencode( $url ) ) . $nonce . $requestContentBase64String; 39 | $hmacsignature = base64_encode( hash_hmac("sha256", $signature, base64_decode( $this->privateKey ), true ) ); 40 | $header_value = "amx " . $this->publicKey . ":" . $hmacsignature . ":" . $nonce; 41 | $headers = array("Content-Type: application/json; charset=utf-8", "Authorization: $header_value"); 42 | curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); 43 | curl_setopt($ch, CURLOPT_URL, $url ); 44 | curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode( $req ) ); 45 | } 46 | // run the query 47 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); 48 | curl_setopt($ch, CURLOPT_FRESH_CONNECT, TRUE); // Do Not Cache 49 | $res = curl_exec($ch); 50 | if ($res === false) throw new Exception('Could not get reply: '.curl_error($ch)); 51 | return $res; 52 | } 53 | 54 | // Some API calls require TradePairId rather than the TradePair so this should store the TradePairId 55 | public function setSymbols() { 56 | $result = json_decode($this->apiCall("GetTradePairs", array() ), true); 57 | 58 | if( $result['Success'] == "true" ) { 59 | $json = $result['Data']; 60 | } else { 61 | throw new Exception("Can't get symbols, Error: " . $result['Error'] ); 62 | } 63 | foreach($json as $pair) { 64 | // creates associative array of key: StandardSymbol (i.e. BTCUSD) value: ExchangeSymbol (i.e. btc_usd) 65 | $this->symbols[ $this->makeStandardSymbol( $pair["Label"] ) ] = $pair["Id"]; 66 | } 67 | } 68 | 69 | public function updatePrices() { 70 | $result = json_decode($this->apiCall("GetMarkets", array() ), true); 71 | if( $result['Success'] == "true" ) { 72 | $json = $result['Data']; 73 | } else { 74 | throw new Exception("Can't get markets, Error: " . $result['Error'] ); 75 | } 76 | foreach($json as $pair) { 77 | $standardSymbol = $this->makeStandardSymbol( $pair["Label"] ); 78 | $this->prices[$standardSymbol]['high'] = $pair['High']; 79 | $this->prices[$standardSymbol]['low'] = $pair['Low']; 80 | $this->prices[$standardSymbol]['bid'] = $pair['BidPrice']; 81 | $this->prices[$standardSymbol]['ask'] = $pair['AskPrice']; 82 | $this->prices[$standardSymbol]['last'] = $pair['LastPrice']; 83 | $this->prices[$standardSymbol]['time'] = ''; // not available on Cryptopia 84 | } 85 | } 86 | 87 | // @todo add setBalance 88 | 89 | Public function getBalance() { 90 | $result = $this->apiCall("GetBalance", array('Currency'=> "") ); // "" for All currency balances 91 | $result = json_decode($result, true); 92 | if( $result['Success'] == "true" ) { 93 | // @todo ADD CODE TO REFORMAT Array to standard 94 | return $result['Data']; 95 | } else { 96 | throw new Exception("Can't get balances, Error: " . $result['Error'] ); 97 | } 98 | } 99 | 100 | Public function getCurrencyBalance( $currency ) { 101 | $result = $this->apiCall("GetBalance", array( 'Currency'=> $currency ) ); 102 | $result = json_decode($result, true); 103 | if( $result['Success'] == "true" ) { 104 | return $result['Data'][0]['Total']; 105 | } else { 106 | throw new Exception("Can't get balance, Error: " . $result['Error'] ); 107 | } 108 | } 109 | 110 | // currency pair $symbol should be in standard Format not exchange format 111 | public function activeOrders( $symbol = "") 112 | { 113 | if($symbol == "") { 114 | $apiParams = array( 'TradePairId'=>"" ); 115 | } else { 116 | $apiParams = array( 'TradePairId'=>$this->getExchangeSymbol($symbol) ); 117 | } 118 | $myOrders = json_decode($this->apiCall("GetOpenOrders", $apiParams), true); 119 | //print_r($myOrders); 120 | // There is a bug in the API if you send no parameters it will return Success:true Error: Market not found. 121 | // Array 122 | // ( 123 | // [Success] => 1 124 | // [Message] => 125 | // [Data] => 126 | // [Error] => Market not found. 127 | // ) 128 | 129 | $orders = array(); 130 | $price = array(); // sort by price 131 | if( $myOrders['Success'] == "true" && $myOrders['Error'] == "") { 132 | foreach ($myOrders['Data'] as $order) { 133 | $orderSymbol = $this->makeStandardSymbol($order["Market"]); // convert to standard format currency pair 134 | $orders[] = ["symbol"=>$orderSymbol, "type"=>$order["Type"], "price"=>$order["Rate"], 135 | "amount"=>$order["Remaining"], "id"=>$order["OrderId"] ]; 136 | if ($order["Type"] == "Sell") { 137 | $price[] = 0 - $order['Rate']; // lowest ask price if first 138 | } else { 139 | $price[] = $order['Rate']; 140 | } 141 | } 142 | if($orders) // If there are any orders 143 | array_multisort($price, SORT_DESC, $orders); // sort orders by price 144 | } else { 145 | throw new Exception("Can't get active orders, Error: " . $myOrders['Error'] ); 146 | } 147 | return $orders; 148 | } 149 | 150 | public function tradeHistory( $symbol, $type = '' ) 151 | { 152 | $apiParams = array( 'TradePairId'=>$this->getExchangeSymbol($symbol) ); 153 | $myOrders = json_decode($this->apiCall("GetTradeHistory", $apiParams), true); 154 | //print_r(array_slice($myOrders['Data'], 0, 5)); 155 | 156 | $orders = array(); 157 | if( $myOrders['Success'] == "true" && $myOrders['Error'] == "") { 158 | foreach ($myOrders['Data'] as $order) { 159 | if($type == '' || $order["Type"] == $type) { // if type is set only get orders of that type 160 | $orderSymbol = $this->makeStandardSymbol($order["Market"]); // convert to standard format currency pair 161 | $orders[] = ["symbol"=>$orderSymbol, "type"=>$order["Type"], "price"=>$order["Rate"], 162 | "amount"=>$order["Amount"], "time"=>strtotime($order["TimeStamp"]) ]; 163 | } 164 | } 165 | } else { 166 | throw new Exception("Can't get active orders, Error: " . $myOrders['Error'] ); 167 | } 168 | return $orders; 169 | } 170 | 171 | public function permissions() { 172 | 173 | } 174 | 175 | public function cancelOrder($id) { 176 | $result = $this->apiCall("CancelTrade", array( 'Type'=>"Trade", 'OrderId'=>$id )); 177 | $result = json_decode($result, true); 178 | if( $result['Success'] == "true" ) { 179 | echo "Order Canceled: " . implode( ", ", $result['Data']) . "\n"; 180 | } else { 181 | throw new Exception("Can't Cancel Order # $id, Error: " . $result['Error']); 182 | } 183 | } 184 | 185 | public function cancelAll() { 186 | if(!$this->activeOrders()) return false; // "No open orders to cancel.\n" 187 | $result = $this->apiCall("CancelTrade", array( 'Type'=>"All" )); 188 | $result = json_decode($result, true); 189 | if( $result['Success'] == "true" ) { 190 | return "Orders Canceled: " . implode( ", ", $result['Data']) . "\n"; 191 | } else { 192 | throw new Exception("Can't Cancel All Orders, Error: " . $result['Error']); 193 | } 194 | } 195 | 196 | public function orderStatus($id) { 197 | 198 | } 199 | 200 | public function placeOrder($symbol, $amount, $price, $side) { 201 | $result = $this->apiCall("SubmitTrade", array( 'Type'=> $side, 'TradePairId'=> $this->getExchangeSymbol($symbol), 202 | 'Rate'=> number_format((float)$price, 8, '.', ''), 'Amount'=> number_format((float)$amount, 8, '.', '') ) ); 203 | $result = json_decode($result, true); 204 | if( $result['Success'] == "true" ) { 205 | return "Order Placed. OrderId:" .$result['Data']['OrderId'] . 206 | " FilledOrders: " . implode( ", ", $result['Data']['FilledOrders']) . "\n"; 207 | } else { 208 | throw new Exception("Can't Place Order, Error: " . $result['Error'] ); //*** die instead of echo 209 | } 210 | } 211 | 212 | public function buy($symbol, $amount, $price) { 213 | return $this->placeOrder($symbol, $amount, $price, 'Buy'); 214 | } 215 | 216 | public function sell($symbol, $amount, $price) { 217 | return $this->placeOrder($symbol, $amount, $price, 'Sell'); 218 | } 219 | 220 | public function marketOrderbook($symbol) 221 | { 222 | $mktOrders = json_decode($this->apiCall("GetMarketOrders", array('TradePairId'=>$this->getExchangeSymbol($symbol))), true); 223 | unset($orders); 224 | if( $mktOrders['Success'] == "true" && $mktOrders['Error'] == "") { 225 | //print_r($mktOrders); 226 | foreach ($mktOrders['Data'] as $orderType => $order) { 227 | foreach($order as $ordersByType) { 228 | // $standardSymbol = $this->getStandardSymbol($symbol); // @todo not yet implemented 229 | $orders[] = ["symbol"=>$symbol, "type"=>$orderType, "price"=>$ordersByType["Price"], 230 | "amount"=>$ordersByType["Volume"] ]; 231 | } 232 | } 233 | } else { 234 | throw new Exception("Can't get orderbook, Error: " . $mktOrders['Error'] ); 235 | } 236 | return $orders; 237 | } 238 | 239 | } 240 | 241 | ?> -------------------------------------------------------------------------------- /exchange.php: -------------------------------------------------------------------------------- 1 | symbols) $this->setSymbols(); 57 | return $this->symbols; 58 | } 59 | // Can be used for currencies and currency pairs to put in only uppercase letters 60 | // note: $exchangeSymbol must be have the base currency first and quote currency second (i.e. eth_btc Not btc_eth). The quote currency is usually BTC, USD, or CNY. 61 | public function makeStandardSymbol($exchangeSymbol) { 62 | // Convert to Uppercase and remove nonletters. 63 | return preg_replace('/[^A-Z]/', '', strtoupper ( $exchangeSymbol )); 64 | } 65 | // @todo not implemented for all exchanges, setSymbols() must create associative array $this->symbols with keys as standard symbols and values as exchange symbols for this function to work. 66 | public function getExchangeSymbol($standardSymbol) { 67 | 68 | //if($standardSymbol == '') return ''; // used to get all symbols 69 | 70 | if(!$this->symbols) $this->setSymbols(); 71 | 72 | if( isset($this->symbols[$standardSymbol]) ) { 73 | return $this->symbols[$standardSymbol]; 74 | } else { 75 | throw new Exception("Can't find symbol '" . $standardSymbol ."'" ); 76 | } 77 | } 78 | 79 | public function getPrices() { 80 | return $this->prices; 81 | } 82 | 83 | // @todo the updateBalance() function for each exchange should use makeStandardSymbol($exchangeSymbol) to get the key for each currency pairs array 84 | public function getBalance() { // this function is overridden until updateBalance() is implemented 85 | // if(!isset($this.balances)) { updateBalance(); } // Not implemented for all exchanges yet 86 | return $this->balances; 87 | } 88 | Public function getCurrencyBalance($currency) { 89 | // @todo Update if not isset() 90 | if(isset($this->balances[$curency]['amount'])) { 91 | return $this->balances[$curency]['amount']; 92 | } 93 | } 94 | 95 | // @todo not implemented for all exchanges, setSymbols() must create associative array $this->symbols with keys as standard symbols and values as exchange symbols or symbolids. 96 | abstract public function setSymbols(); 97 | 98 | // abstract public function getFee($symbol); // @todo Not implemented for ct exchange yet 99 | 100 | // @todo the updatePrices() function for each exchange should use makeStandardSymbol($exchangeSymbol) to get the key for each currency pairs array 101 | abstract public function updatePrices(); 102 | 103 | // abstract public function updateBalance(); // Not implemented for all exchanges yet 104 | 105 | // @todo ??? allow passing a $symbol for all exchanges? 106 | abstract public function activeOrders(); 107 | 108 | abstract public function permissions(); 109 | 110 | abstract public function cancelOrder($id); 111 | // is function should be overridden if exchange has cancel all function call 112 | // @todo write generalized cancel all that loops through active orders, see btceAPI 113 | abstract public function cancelAll(); 114 | 115 | abstract public function orderStatus($id); 116 | 117 | // This should create a buy / sell order at the exchange for [amount] of [asset] at [price] and return the orderId 118 | // @todo should implement getExchangeSymbol($standardSymbol) for each exchange 119 | abstract public function buy($symbol, $amount, $price); // some exchanges may have additional parameters 120 | abstract public function sell($symbol, $amount, $price); // some exchanges may have additional parameters 121 | 122 | 123 | // ----- Data Calculation functions ----- 124 | 125 | // note: assumes buy offers are in descending order by price 126 | public function highestBid($offers, $depth = 0, $type = "Buy") { 127 | $total_amount = 0; 128 | $highest_bid = 0; 129 | if($offers) // if there are any offers 130 | foreach( $offers as $item ) 131 | { 132 | if( $item["type"] == $type ) { 133 | //echo "type: " . $item["type"] . " price: " . $item['price'] . " amount: " .$item['amount'] . "\n"; 134 | $total_amount += floatval($item['amount']); 135 | 136 | if( $highest_bid == 0 && $total_amount >= $depth ) // Go $1000 deep into the bids 137 | { 138 | $highest_bid = $item['price']; 139 | break; 140 | } 141 | } 142 | } 143 | return $highest_bid; 144 | } 145 | 146 | // note: assumes sell offers are in accenting order by price 147 | public function lowestAsk($offers, $depth = 0, $type = "Sell") { 148 | return $this->highestBid($offers, $depth, $type); 149 | } 150 | 151 | // takes an array of of offers/orders and returns the volume within a price range 152 | public function volume($offers, $lowerPriceLimit = 0, $upperPriceLimit = PHP_FLOAT_MAX) { 153 | $total_vol = 0; 154 | foreach( $offers as $item ) 155 | { 156 | //echo "price: " . $item['Price'] . " amount: " .$item['Volume'] . "\n"; 157 | if( $item['price'] >= $lowerPriceLimit && $item['price'] <= $upperPriceLimit ) { 158 | $total_vol += floatval($item['amount']); 159 | } 160 | } 161 | return $total_vol; 162 | } 163 | 164 | } // end of class Exchange 165 | 166 | ?> -------------------------------------------------------------------------------- /nicehashAPI.php: -------------------------------------------------------------------------------- 1 | privateKey = $priv; 10 | $this->publicKey = $pub; 11 | 12 | $result = $this->api_nicehash( array() ); 13 | 14 | if( !isset($result['result']['api_version']) ) { 15 | throw new Exception("Can't Connect to Nichhash API"); 16 | } 17 | return true; 18 | } 19 | 20 | private function api_nicehash($req) { 21 | static $ch = null; 22 | $ch = curl_init(); 23 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 24 | $url = "https://api.nicehash.com/api?"; 25 | if ($req) { foreach ($req as $rk => $r ) { $url = $url . $rk . '=' . $r . '&'; } } 26 | curl_setopt($ch, CURLOPT_URL, $url ); 27 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); 28 | $res = curl_exec($ch); 29 | if ($res === false) throw new Exception('Could not get reply: '.curl_error($ch)); 30 | $result = json_decode($res, true); 31 | return $result; 32 | } 33 | 34 | public function getOrders($location) { 35 | $args = array(); 36 | $args['method'] = 'orders.get'; 37 | $args['location'] = $location; 38 | $args['algo'] = 22; // 22 = CryptoNight 39 | $result = $this->api_nicehash($args); 40 | if(isset($result['result']['error'])) { echo "Error: " . $result['result']['error'] . PHP_EOL; return; }; 41 | return $result['result']['orders']; 42 | } 43 | 44 | public function myOrders($location) { 45 | $args = array(); 46 | $args['method'] = 'orders.get&my'; 47 | $args['id'] = $this->publicKey; 48 | $args['key'] = $this->privateKey; 49 | $args['location'] = $location; 50 | $args['algo'] = 22; // 22 = CryptoNight 51 | $result = $this->api_nicehash($args); 52 | if(isset($result['result']['error'])) { echo "Error: " . $result['result']['error'] . PHP_EOL; return; }; 53 | return $result['result']['orders']; 54 | } 55 | 56 | protected function numworkers($var) 57 | { 58 | //echo $var['accepted_speed'] . " " . (boolval($var['accepted_speed']) ? 'true' : 'false') . " "; 59 | return boolval($var['workers']); 60 | } 61 | 62 | // public function lowestOrderPrice($orders, $totalhash) 63 | // https://api.nicehash.com/api?method=stats.global.current&location=1 64 | 65 | public function lowestPrice($orders, $depth) { 66 | 67 | $orders = array_filter($orders, array( $this, "numworkers") ); 68 | $orders = array_reverse($orders); 69 | //print_r(array_slice($orders, 0, 10)); 70 | 71 | $workers_sum = 0; 72 | $price = 0; 73 | foreach($orders as $order) { 74 | $workers_sum += $order['workers']; 75 | if($workers_sum > $depth) { 76 | return $order['price']; 77 | } 78 | } 79 | } 80 | 81 | public function setLimit($order, $location, $limit = 0.01) { 82 | if($order['limit_speed'] != $limit){ 83 | $args = array(); 84 | $args['method'] = 'orders.set.limit'; 85 | $args['id'] = $this->publicKey; 86 | $args['key'] = $this->privateKey; 87 | $args['location'] = $location; 88 | $args['algo'] = 22; // 22 = CryptoNight 89 | $args['order'] = $order['id']; 90 | $args['limit'] = $limit; 91 | $result = $this->api_nicehash($args); 92 | if(isset($result['result']['error'])) return "Error: " . $result['result']['error']; 93 | return $result['result']['success']; 94 | } 95 | } 96 | 97 | public function setPrice($order, $location, $max_price, $price = 0.01) { 98 | if($order['price'] < $price){ 99 | $args = array(); 100 | $args['method'] = 'orders.set.price'; 101 | $args['id'] = $this->publicKey; 102 | $args['key'] = $this->privateKey; 103 | $args['location'] = $location; 104 | $args['algo'] = 22; // 22 = CryptoNight 105 | $args['order'] = $order['id']; 106 | $args['price'] = $price; 107 | $result = $this->api_nicehash($args); 108 | if(isset($result['result']['error'])) return "Error: " . $result['result']['error']; 109 | return $result['result']['success']; 110 | } 111 | 112 | if($order['price'] > $price){ 113 | $args = array(); 114 | $args['method'] = 'orders.set.price.decrease'; 115 | $args['id'] = $this->publicKey; 116 | $args['key'] = $this->privateKey; 117 | $args['location'] = $location; 118 | $args['algo'] = 22; // 22 = CryptoNight 119 | $args['order'] = $order['id']; 120 | $result = $this->api_nicehash($args); 121 | if(isset($result['result']['error'])) return "Error: " . $result['result']['error']; 122 | 123 | // cancel order and relist if still above max_price 124 | if( substr($result['result']['success'], 0, 23 ) == "New order price set to:" ) { 125 | $return_price = substr($result['result']['success'], 23 ); 126 | if(floatval($return_price) > $max_price && intval($order['workers']) > 0) { 127 | //print_r($order); 128 | $order['price'] = $price; 129 | echo $this->removeOrder($order, $location) . PHP_EOL; 130 | return $this->createOrder($order, $location) . PHP_EOL; 131 | } 132 | } 133 | 134 | return $result['result']['success']; 135 | } 136 | } 137 | 138 | public function removeOrder($order, $location) { 139 | $args = array(); 140 | $args['method'] = 'orders.remove'; 141 | $args['id'] = $this->publicKey; 142 | $args['key'] = $this->privateKey; 143 | $args['location'] = $location; 144 | $args['algo'] = 22; // 22 = CryptoNight 145 | $args['order'] = $order['id']; 146 | sleep(2); 147 | $result = $this->api_nicehash($args); 148 | sleep(10); // extra time for order to cancel and balance to reset 149 | if(isset($result['result']['error'])) { echo "Error: " . $result['result']['error'] . PHP_EOL; return; }; 150 | return $result['result']['success']; 151 | } 152 | 153 | public function createOrder($order, $location) { 154 | $args = array(); 155 | $args['method'] = 'orders.create'; 156 | $args['id'] = $this->publicKey; 157 | $args['key'] = $this->privateKey; 158 | $args['location'] = $location; 159 | $args['algo'] = 22; // 22 = CryptoNight 160 | $args['amount'] = $order['btc_avail']; 161 | $args['price'] = $order['price']; 162 | $args['limit'] = $order['limit_speed']; 163 | $args['pool_host'] = $order['pool_host']; 164 | $args['pool_port'] = $order['pool_port']; 165 | $args['pool_user'] = $order['pool_user']; 166 | $args['pool_pass'] = $order['pool_pass']; 167 | //print_r($order); 168 | sleep(10); // extra time for order to cancel and balance to reset 169 | $result = $this->api_nicehash($args); 170 | if(isset($result['result']['error'])) { echo "Error: " . $result['result']['error'] . PHP_EOL; return; }; 171 | return $result['result']['success']; 172 | } 173 | 174 | } 175 | 176 | ?> -------------------------------------------------------------------------------- /nicehashbot.php: -------------------------------------------------------------------------------- 1 | > host: bip.ms-pool.net.ua port: 7777 username: .2000000 password: x 19 | * US >> host: pool.democats.org port: 45590 username: .2000000 passoword: x 20 | * 21 | * Select CryptoNight Algorithm 22 | * Add one standard order for EU hashing sever and one order for US hasing sever 23 | * https://www.nicehash.com/index.jsp?p=orders 24 | * 25 | * Run this script and schedule it to run every 10-15 Mins. 26 | */ 27 | 28 | // Nicehash API Id and Key 29 | $NICEHASH_ID = '######'; 30 | $NICEHASH_KEY = 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'; 31 | 32 | $trade_pair = "BIPBTC"; 33 | $one_coin_unit = 1000000000000; 34 | 35 | // CryptoNote pools API 36 | $bip_pools = [ 37 | ["bip.crypto-coins.club", "http://bip.crypto-coins.club:8118"], 38 | ["democats.org", "http://pool.democats.org:7693"], 39 | ["bip.ms-pool.net.ua", "http://bip.ms-pool.net.ua:8117"], 40 | ["bip.mypool.name", "http://bip.mypool.name:18874"], 41 | ["bip.cryptonotepool.com", "http://bip.cryptonotepool.com:8121"] 42 | ]; 43 | 44 | 45 | try { 46 | 47 | //----- Get My NiceHash open orders 48 | $nh = New Nicehash( $NICEHASH_KEY, $NICEHASH_ID ); 49 | 50 | $myEUOrders = $nh->myOrders(0); 51 | echo "My Orders: (EU)\n"; 52 | print_r($myEUOrders); 53 | 54 | if (isset($myEUOrders[0]['alive']) && $myEUOrders[0]['alive'] == 1) { 55 | $my_current_hashrate = $myEUOrders[0]['accepted_speed'] * 1000000000; 56 | } else { 57 | $my_current_hashrate = 0; 58 | } 59 | 60 | $myUSOrders = $nh->myOrders(1); 61 | echo "My Orders: (US)\n"; 62 | print_r($myUSOrders); 63 | 64 | if (isset($myUSOrders[0]['alive']) && $myUSOrders[0]['alive'] == 1) { 65 | $my_current_hashrate += $myUSOrders[0]['accepted_speed'] * 1000000000; 66 | } 67 | echo "My Current Hashrate: $my_current_hashrate \n"; 68 | 69 | 70 | //----- Get Bid/Ask Prices from Cryptopia 71 | $ct = New Cryptopia( '', '' ); 72 | $ct->updatePrices(); // Gets all currency prices, could be modified to just get one currency pair 73 | $prices = $ct->getPrices(); 74 | echo $trade_pair . "\n"; 75 | echo "Ask Price: " . $ask_price = $prices[$trade_pair]['ask'] . "\n"; 76 | echo "Bid Price: " . $bid_price = $prices[$trade_pair]['bid'] . "\n"; 77 | $mid_price = ( $prices[$trade_pair]['ask'] + $prices[$trade_pair]['bid'] ) / 2; 78 | echo "Mid Price: $mid_price \n"; 79 | 80 | //----- Select between "ask" "mid" "bid" or "custom" price for max price to pay for mining each coin 81 | //$price = $bid_price; // bid price 82 | //$price = $ask_price; // ask price 83 | $price = $mid_price; // avg of bid and ask price 84 | //$price = .000026; // custom price override 85 | 86 | 87 | //---- Get Network Hashrate and block reward from Pool 88 | $all_pool_stats = api_poolStats(); 89 | $net_hashrate = api_pool_hashrate($all_pool_stats); 90 | 91 | 92 | $pool_stats = $all_pool_stats[0]; 93 | $net_dif = $pool_stats['network']['difficulty']; 94 | echo "Net Dif: " . $net_dif . "\n"; 95 | echo "coinDifficultyTarget: " . $pool_stats['config']['coinDifficultyTarget'] . "\n"; 96 | $target_hashrate = $net_dif / $pool_stats['config']['coinDifficultyTarget']; 97 | echo "Net target hashrate: $target_hashrate \n"; 98 | $block_reward = $pool_stats['network']['reward'] / $one_coin_unit; 99 | echo "Block Reward: " . $block_reward . "\n"; 100 | //$bip_daily_reward = $block_reward * (3600 / $pool_stats['config']['coinDifficultyTarget']) * 24; //based on target hashrate 101 | $bip_daily_reward = $block_reward * (3600 / ($net_dif / $net_hashrate)) * 24; //based on current network hashrate 102 | echo "Daily Reward: $bip_daily_reward bip " . 103 | $bip_daily_reward * $price . " btc \n"; 104 | 105 | $max_net_hashrate = $net_dif / ($pool_stats['config']['coinDifficultyTarget']); // 120 sec target 106 | echo "max_net_hashrate: $max_net_hashrate \n"; 107 | $min_net_hashrate = $net_dif / ($pool_stats['config']['coinDifficultyTarget'] * 30); // 30 times the 2 min target i.e. 60 min 108 | echo "min_net_hashrate: $min_net_hashrate \n"; 109 | 110 | $net_hashrate = $net_hashrate - $my_current_hashrate; 111 | if ($net_hashrate < 0) $net_hashrate = 0; 112 | echo "Network Hashrate minus my hashrate: $net_hashrate" . PHP_EOL; 113 | 114 | $max_cost_per_mh = 0.90 * $block_reward * $price * 1000000 * 3600 * 24 / $net_dif; // 10% for fees and rejected shares 115 | echo "Max cost: $max_cost_per_mh \n"; 116 | 117 | if ($min_net_hashrate - $net_hashrate < 0 ) 118 | $my_min_hashrate = 0; 119 | else 120 | $my_min_hashrate = ceil(($min_net_hashrate - $net_hashrate)/1000000 * 100) /100; //round up to 2 decimal places 121 | echo "my min hashrate: $my_min_hashrate \n"; 122 | 123 | $my_max_hashrate = number_format((float) ($max_net_hashrate - $net_hashrate)/1000000, 2, '.', ''); 124 | $half_max_net_hashrate = number_format((float) ($max_net_hashrate/2)/1000000, 2, '.', ''); 125 | if($my_max_hashrate > $half_max_net_hashrate) 126 | $my_max_hashrate = $half_max_net_hashrate; 127 | echo "my max hashrate: $my_max_hashrate \n"; 128 | 129 | //----- Get NiceHash Order Book 130 | $orders = $nh->getOrders(0); 131 | //print_r(array_slice($orders, 0, 3)); 132 | $EUprice = $nh->lowestPrice( $orders, 1000 ) + .0001; 133 | $bip_price = $EUprice / 1000000 * $net_hashrate / $bip_daily_reward; 134 | $bip_price = number_format((float) $bip_price, 8, '.', ''); 135 | echo "EU Price 1000 workers deep: $EUprice BTC/MH/day $bip_price BTC/BIP\n"; 136 | 137 | $USprice = $nh->lowestPrice( $nh->getOrders(1), 1000 ) + .0001; 138 | $bip_price = $USprice / 1000000 * $net_hashrate / $bip_daily_reward; 139 | $bip_price = number_format((float) $bip_price, 8, '.', ''); 140 | echo "US Price 1000 workers deep: $USprice BTC/MH/day $bip_price BTC/BIP\n"; 141 | 142 | sleep(2); 143 | 144 | //----- Update My NiceHash Orders 145 | if ( isset($myEUOrders[0]['alive']) && $myEUOrders[0]['alive'] == 1 && $EUprice != 0 && ($EUprice < $USprice OR !isset($myUSOrders[0]['alive'])) ) { 146 | echo "update EU miner\n"; 147 | 148 | if ($max_cost_per_mh > $EUprice) 149 | $speed_limit = $my_max_hashrate; 150 | else if ($my_min_hashrate > 0.01) 151 | $speed_limit = $my_min_hashrate; 152 | else 153 | $speed_limit = 0.01; 154 | 155 | echo $nh->setLimit($myEUOrders[0], 0, $speed_limit) . PHP_EOL; 156 | 157 | if($my_min_hashrate > 0 && $max_cost_per_mh < $EUprice) $max_cost_per_mh = $EUprice; // raise the price you are willing to pay when the net hashrate is below the min hashrate 158 | 159 | if ($EUprice > $max_cost_per_mh) $EUprice = $max_cost_per_mh; 160 | sleep(2); 161 | echo $nh->setPrice($myEUOrders[0], 0, $max_cost_per_mh, $EUprice) . PHP_EOL; 162 | if (isset($myUSOrders[0]['alive']) && $myUSOrders[0]['alive'] == 1) { 163 | sleep(2); 164 | $price = $max_cost_per_mh*.75; 165 | if ($price > $USprice) { 166 | $price = $USprice; 167 | } 168 | echo $nh->setLimit($myUSOrders[0], 1, 0.01) . PHP_EOL; 169 | sleep(2); 170 | echo $nh->setPrice($myUSOrders[0], 1, $max_cost_per_mh, $price) . PHP_EOL; 171 | } 172 | 173 | } else if ($USprice != 0 && isset($myUSOrders[0]['alive']) && $myUSOrders[0]['alive'] == 1) { 174 | echo "update US miner\n"; 175 | 176 | if ($max_cost_per_mh > $USprice) 177 | $speed_limit = $my_max_hashrate; 178 | else if ($my_min_hashrate > 0.01) 179 | $speed_limit = $my_min_hashrate; 180 | else 181 | $speed_limit = 0.01; 182 | echo $nh->setLimit($myUSOrders[0], 1, $speed_limit) . PHP_EOL; 183 | 184 | if($my_min_hashrate > 0 && $max_cost_per_mh < $USprice) $max_cost_per_mh = $USprice; // raise the price you are willing to pay when the net hashrate is below the min hashrate 185 | 186 | if ($USprice > $max_cost_per_mh) $USprice = $max_cost_per_mh; 187 | sleep(2); 188 | echo $nh->setPrice($myUSOrders[0], 1, $max_cost_per_mh, $USprice) . PHP_EOL; 189 | if (isset($myEUOrders[0]['alive']) && $myEUOrders[0]['alive'] == 1) { 190 | sleep(2); 191 | $price = $max_cost_per_mh*.75; 192 | if ($price > $EUprice) { 193 | $price = $EUprice; 194 | } 195 | echo $nh->setLimit($myEUOrders[0], 0, 0.01) . PHP_EOL; 196 | sleep(2); 197 | echo $nh->setPrice($myEUOrders[0], 0, $max_cost_per_mh, $price) . PHP_EOL; 198 | } 199 | } 200 | } catch(Exception $e) { 201 | echo '' . $e->getMessage() . PHP_EOL; 202 | } 203 | 204 | //----- Mining Pool Stats 205 | function api_poolStats() { 206 | global $bip_pools; 207 | static $ch = null; 208 | $ch = curl_init(); 209 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 210 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); 211 | foreach ($bip_pools as $pool) { 212 | $url = $pool[1] . "/stats"; 213 | curl_setopt($ch, CURLOPT_URL, $url ); 214 | $res = curl_exec($ch); 215 | if ($res === false) echo "Can't connect to pool: " . $pool[0] . " Error:" . curl_error($ch) . PHP_EOL; 216 | else $results[] = json_decode($res, true); 217 | } 218 | if ($results === false) throw new Exception('Could not connect to any mining pools'); 219 | return $results; 220 | } 221 | 222 | function api_pool_hashrate($pool_stats) { 223 | $net_hashrate = 0; 224 | foreach ($pool_stats as $pool) { 225 | $pool_hashrate = $pool['pool']['hashrate']; 226 | echo "Pool Hashrate: $pool_hashrate" . PHP_EOL; 227 | $net_hashrate += $pool_hashrate; 228 | } 229 | echo "Network Hashrate: $net_hashrate" . PHP_EOL; 230 | return $net_hashrate; 231 | } 232 | 233 | ?> 234 | --------------------------------------------------------------------------------