diff --git a/config_default.php b/config_default.php index c329046..4117d18 100644 --- a/config_default.php +++ b/config_default.php @@ -5,7 +5,7 @@ date_default_timezone_set('UTC'); if (version_compare(phpversion(),"8.0.0",'>=') - || version_compare(phpversion(),"7.0.0",'<')) +|| version_compare(phpversion(),"7.0.0",'<')) die ('requires php version 7.x.x, running ' . phpversion()); ini_set('memory_limit', '64M'); # memory limit, set '-1' for unlimited, default 32M @@ -33,8 +33,10 @@ /* telegram settings */ -$config['chatId'] = 'chatId'; # default telegram chat id -$config['chatPath'] = 'https://api.telegram.org/bot132'; # bot API path and key +// bot name aaaaaa +$config['chatPath'] = 'https://api.telegram.org/bot000000000:AAAAAAAAA_AAAAAAAA_AAAAAAAA'; # bot API path and key +// user name aaaaaa +$config['chatId'] = '111111111'; # chat id for bot and user $config['chatText'] = 'message failed'; /* database arrays */ @@ -226,6 +228,13 @@ function config_exchange($config) { $config['hist_pairs'] = array('BTC/USDT', 'ETH/USDT', 'LTC/USDT', 'ETC/USDT', 'XRP/USDT', 'EOS/USDT', 'BCH/USDT', 'BSV/USDT', 'TRX/USDT'); break; + case 'etherscan': + $config['method'] = 'GET'; + $config['api_key'] = '000'; + $config['url'] = 'https://api.etherscan.io/api?'; + $config['address_eth'] = '0x000'; + break; + case 'uniswap': $config['url'] = 'https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2'; $config['address_uniswap'] = '0x0000000000000000000000000000000000000000'; diff --git a/functions.analysis.php b/functions.analysis.php index 3a680b8..241cbff 100644 --- a/functions.analysis.php +++ b/functions.analysis.php @@ -5,7 +5,7 @@ function technical_analysis($config, $pair_id = FALSE) { $query = "SELECT DISTINCT pair, period, source, currency, history_start FROM asset_pairs WHERE analyse"; - if($pair_id) $query .= " AND pair_id = " . $pair_id; + if ($pair_id) $query .= " AND pair_id = " . $pair_id; $pairs = query($query, $config); $stop = $config['timestamp']; @@ -18,145 +18,155 @@ function technical_analysis($config, $pair_id = FALSE) { $rsios = 25; // oversold, 'rsi'.$n.'os' $ema = array(6, 12, 26, 50, 100, 200); // 'ema'.$n, crossover upwards 'ema'.$n.'cu', crossover downwards 'ema'.$n.'cd' $roc = array(1, 2, 4, 6, 12, 24); // 'roc'.$n - $corr = array('BTC' => array(50), - 'ETH' => array(50)); // 'corr'.$n.'btc' + $corr = array( + 'BTC' => array(50), + 'ETH' => array(50) + ); // 'corr'.$n.'btc' foreach ($pairs as $pair) { - $period_txt = $config['period'][$pair['period']]; - $period = $pair['period'] * 60000; - $start = $stop - $period * ($points + $points_buffer); - - $query = "SELECT history_id, timestamp, close FROM price_history - WHERE pair = '" . $pair['pair'] . "' - AND source = '" . $pair['source'] . "' - AND period = '" . $period_txt . "' - AND timestamp >= " . $start . " - AND timestamp <= " . $stop . " - ORDER BY timestamp ASC"; - $hist = query($query, $config); - if($config['debug']) echo $query . PHP_EOL; - if(empty($hist)) continue 1; - //var_dump($hist); - //var_dump($query); - - $last = $hist[0]['timestamp'] - $period; - $missing_data = FALSE; - $i = 0; - foreach ($hist as $h) { - $diff_obs = $h['timestamp'] - $last; - if ($period !== $diff_obs) { - $missing_data = TRUE; - $missing_obs = $h['timestamp'] - $period; - $missing_array = $i; - } - $last = $h['timestamp']; - $i++; - } - if($missing_data) { - echo 'missing data at array position ' . $missing_array . ',
time ' . date('Y-m-d H:i T', $missing_obs / 1000) . ',
timestamp ' . $missing_obs . ',
period ' . $period . '
'; - var_dump($hist[$missing_array - 1]); - var_dump($hist[$missing_array]); - continue 1; - } - - $count = count($hist); - $dc = array_column($hist, 'close'); - - foreach($rsi as $n) { - $r = trader_rsi($dc, $n); - $j = 0; - for($i = 0; $i < $count; $i++) { - if(isset($r[$i])) { - $hist[$i]['rsi'.$n] = $r[$i]; - if(isset($r[$j])) { - if($r[$j] <= $rsiob && $r[$i] > $rsiob) - $hist[$i]['rsi'.$n.'ob'] = 1; - else - $hist[$i]['rsi'.$n.'ob'] = 0; - if($r[$j] >= $rsios && $r[$i] < $rsios) - $hist[$i]['rsi'.$n.'os'] = 1; - else - $hist[$i]['rsi'.$n.'os'] = 0; - } + $period_txt = $config['period'][$pair['period']]; + $period = $pair['period'] * 60000; + $start = $stop - $period * ($points + $points_buffer); + + $query = " + SELECT history_id, timestamp, close FROM price_history + WHERE pair = '" . $pair['pair'] . "' + AND source = '" . $pair['source'] . "' + AND period = '" . $period_txt . "' + AND timestamp >= " . $start . " + AND timestamp <= " . $stop . " + ORDER BY timestamp ASC + "; + $hist = query($query, $config); + if ($config['debug']) echo $query . PHP_EOL; + if (empty($hist)) continue 1; + + $last = $hist[0]['timestamp'] - $period; + $missing_data = FALSE; + $i = 0; + foreach ($hist as $h) { + $diff_obs = $h['timestamp'] - $last; + if ($period !== $diff_obs) { + $missing_data = TRUE; + $missing_obs = $h['timestamp'] - $period; + $missing_array = $i; + } + $last = $h['timestamp']; + $i++; + } + if ($missing_data) { + echo ' + missing data at array position ' . $missing_array . ',
+ time ' . date('Y-m-d H:i T', $missing_obs / 1000) . ',
+ timestamp ' . $missing_obs . ',
+ period ' . $period . '
+ '; + var_dump($hist[$missing_array - 1]); + var_dump($hist[$missing_array]); + continue 1; + } + + $count = count($hist); + $dc = array_column($hist, 'close'); + + foreach ($rsi as $n) { + $r = trader_rsi($dc, $n); + $j = 0; + for ($i = 0; $i < $count; $i++) { + if (isset($r[$i])) { + $hist[$i]['rsi'.$n] = $r[$i]; + if (isset($r[$j])) { + if ($r[$j] <= $rsiob && $r[$i] > $rsiob) + $hist[$i]['rsi'.$n.'ob'] = 1; + else + $hist[$i]['rsi'.$n.'ob'] = 0; + if ($r[$j] >= $rsios && $r[$i] < $rsios) + $hist[$i]['rsi'.$n.'os'] = 1; + else + $hist[$i]['rsi'.$n.'os'] = 0; } - $j = $i; } + $j = $i; } - - foreach($ema as $n) { - $r = trader_ema($dc, $n); - $j = 0; - for($i = 0; $i < $count; $i++) { - if(isset($r[$i])) { - $hist[$i]['ema'.$n] = $r[$i]; - if(isset($r[$j])) { - if($dc[$j] <= $r[$j] && $dc[$i] > $r[$i]) { - $hist[$i]['ema'.$n.'cu'] = 1; // crossover upwards - } else { - $hist[$i]['ema'.$n.'cu'] = 0; - } - if($dc[$j] >= $r[$j] && $dc[$i] < $r[$i]) { - $hist[$i]['ema'.$n.'cd'] = 1; // crossover downwards - } else { - $hist[$i]['ema'.$n.'cd'] = 0; - } + } + + foreach ($ema as $n) { + $r = trader_ema($dc, $n); + $j = 0; + for ($i = 0; $i < $count; $i++) { + if (isset($r[$i])) { + $hist[$i]['ema'.$n] = $r[$i]; + if (isset($r[$j])) { + if ($dc[$j] <= $r[$j] && $dc[$i] > $r[$i]) { + $hist[$i]['ema'.$n.'cu'] = 1; // crossover upwards + } else { + $hist[$i]['ema'.$n.'cu'] = 0; + } + if ($dc[$j] >= $r[$j] && $dc[$i] < $r[$i]) { + $hist[$i]['ema'.$n.'cd'] = 1; // crossover downwards + } else { + $hist[$i]['ema'.$n.'cd'] = 0; } } - $j = $i; } + $j = $i; } + } - foreach($roc as $n) { - $r = trader_roc($dc, $n); - for($i = 0; $i < $count; $i++) { - if(isset($r[$i])) - $hist[$i]['roc'.$n] = $r[$i]; - } + foreach ($roc as $n) { + $r = trader_roc($dc, $n); + for ($i = 0; $i < $count; $i++) { + if (isset($r[$i])) + $hist[$i]['roc'.$n] = $r[$i]; } - - foreach($corr as $key => $array) { - $query = "SELECT DISTINCT pair_id, pair, source, currency, history_start FROM asset_pairs - WHERE analyse - AND period = " . $pair['period'] . " - AND pair LIKE '%" . $key . "/USD%'"; + } + + foreach ($corr as $key => $array) { + $query = " + SELECT DISTINCT pair_id, pair, source, currency, history_start FROM + WHERE analyse + AND period = " . $pair['period'] . " + AND pair LIKE '%" . $key . "/USD%' + "; + $res = query($query, $config); + if (!empty($res)) { + $query = " + SELECT timestamp, close FROM price_history + WHERE pair = '" . $res[0]['pair'] . "' + AND source = '" . $res[0]['source'] . "' + AND period = '" . $period_txt . "' + AND timestamp >= " . $hist[0]['timestamp'] . " + AND timestamp <= " . $hist[$count-1]['timestamp'] . " + ORDER BY timestamp ASC + "; $res = query($query, $config); - if(!empty($res)) { - $query = "SELECT timestamp, close FROM price_history - WHERE pair = '" . $res[0]['pair'] . "' - AND source = '" . $res[0]['source'] . "' - AND period = '" . $period_txt . "' - AND timestamp >= " . $hist[0]['timestamp'] . " - AND timestamp <= " . $hist[$count-1]['timestamp'] . " - ORDER BY timestamp ASC"; - $res = query($query, $config); - if(!empty($res) && count($res) == $count) { - $cc = array_column($res, 'close'); - foreach($array as $n) { - $r = trader_correl($dc, $cc, $n); - for($i = 0; $i < $count; $i++) { - if(isset($r[$i])) - $hist[$i]['corr'.$n.$key] = $r[$i]; - } + if (!empty($res) && count($res) == $count) { + $cc = array_column($res, 'close'); + foreach ($array as $n) { + $r = trader_correl($dc, $cc, $n); + for ($i = 0; $i < $count; $i++) { + if (isset($r[$i])) + $hist[$i]['corr'.$n.$key] = $r[$i]; } } } } - - $omit = array('history_id', 'timestamp', 'open', 'high', 'low', 'close', 'volume'); - foreach($hist as $h) { - $sep = ''; - $query = "UPDATE price_history SET "; - foreach($h as $key => $val) { - if(!in_array($key, $omit, TRUE)) { - $query .= $sep . $key . " = '" . $val . "'"; - $sep = ','; - } + } + + $omit = array('history_id', 'timestamp', 'open', 'high', 'low', 'close', 'volume'); + foreach ($hist as $h) { + $sep = ''; + $query = "UPDATE price_history SET "; + foreach ($h as $key => $val) { + if (!in_array($key, $omit, TRUE)) { + $query .= $sep . $key . " = '" . $val . "'"; + $sep = ','; } - $query .= " WHERE history_id = " . $h['history_id']; - query($query, $config); - //die; } + $query .= " WHERE history_id = " . $h['history_id']; + query($query, $config); + } } diff --git a/functions.history.php b/functions.history.php index ff7b46e..2563526 100644 --- a/functions.history.php +++ b/functions.history.php @@ -4,17 +4,25 @@ function history_orders($config) { - # make query string + // make query string switch ($config['exchange']) { case 'bitmax': $config['api_request'] = 'order/hist/current'; - $config['url'] .= $config['group'] . $config['order_history'] . '?n=1000&symbol=' . $config['pair']; - break; + $config['url'] .= + $config['group'] . + $config['order_history'] . + '?n=1000&symbol=' . + $config['pair'] + ; + break; case 'okex': - $config['api_request'] = '/api/spot/v3/orders?instrument_id=' . str_replace('/', '-', $config['pair']) - . '&state=2'; + $config['api_request'] = + '/api/spot/v3/orders' . + '?instrument_id=' . str_replace('/', '-', $config['pair']) + . '&state=2' + ; $config['url'] .= $config['api_request']; - break; + break; } return info($config); @@ -25,55 +33,61 @@ function history_orders($config) { function check_transaction($config, $transaction_id) { - $values = array(); - $values['filterquery'] = " WHERE transaction_id = " . $transaction_id; - $t = query('get_transactions', $config, $values); - - $config['exchange'] = $t[0]['exchange']; - $config = config_exchange($config); - $config['method'] = 'GET'; - - switch($t[0]['exchange']) { + $values = array(); + $values['filterquery'] = " WHERE transaction_id = " . $transaction_id; + $t = query('get_transactions', $config, $values); - case 'bitmax': - $config['api_request'] = 'order/status'; - $config['url'] .= $config['group'] . $config['orders_status'] - . '?orderId=' . $t[0]['exchange_transaction_id']; - break; - case 'okex': - $config['api_request'] = $config['orders_status'] . $t[0]['exchange_transaction_id'] - . '?instrument_id=' - . str_replace('/', '-', $t[0]['pair_asset']); - $config['url'] .= $config['orders_status'] . $t[0]['exchange_transaction_id']; - break; + $config['exchange'] = $t[0]['exchange']; + $config = config_exchange($config); + $config['method'] = 'GET'; - } + switch($t[0]['exchange']) { + case 'bitmax': + $config['api_request'] = 'order/status'; + $config['url'] .= + $config['group'] . + $config['orders_status'] . + '?orderId=' . $t[0]['exchange_transaction_id'] + ; + break; + case 'okex': + $config['api_request'] = + $config['orders_status'] . + $t[0]['exchange_transaction_id'] . + '?instrument_id=' . str_replace('/', '-', $t[0]['pair_asset']) + ; + $config['url'] .= + $config['orders_status'] . + $t[0]['exchange_transaction_id'] + ; + break; + } - $transaction = info($config); + $transaction = info($config); - if($t[0]['exchange'] == 'bitmax') { - if($transaction['code'] !== 0) { - return FALSE; - } else { - $transaction = $transaction[0]['data']; - } + if ($t[0]['exchange'] == 'bitmax') { + if ($transaction['code'] !== 0) { + return FALSE; + } else { + $transaction = $transaction[0]['data']; } + } - if($t[0]['exchange'] == 'okex') { - if($transaction['error_code'] !== 0) { - return FALSE; - } - } else { - $transaction = $transaction[0]; + if ($t[0]['exchange'] == 'okex') { + if ($transaction['error_code'] !== 0) { + return FALSE; } + } else { + $transaction = $transaction[0]; + } - $transaction['exchange'] = $t[0]['exchange']; + $transaction['exchange'] = $t[0]['exchange']; - /* map array to exchange-specific format */ - $transaction = map_transaction('', $transaction, $config); - query('update_transaction', $config, $transaction); + /* map array to exchange-specific format */ + $transaction = map_transaction('', $transaction, $config); + query('update_transaction', $config, $transaction); - return $transaction; + return $transaction; } @@ -82,96 +96,103 @@ function check_transaction($config, $transaction_id) { function update_transactions($config) { // select all possible combinations of exchange and pair_asset - $query = "SELECT DISTINCT exchange, pair_asset FROM transactions"; - $sub_query = " WHERE exchange_transaction_status != 'cancelled' - AND from_asset != to_asset"; - if(!empty($config['exchange'])) { + $query = " + SELECT DISTINCT + exchange, + pair_asset + FROM transactions + "; + $sub_query = " + WHERE exchange_transaction_status != 'cancelled' + AND from_asset != to_asset + "; + if (!empty($config['exchange'])) { $sub_query .= " AND exchange = '" . $config['exchange'] . "'"; } else { $sub_query .= " AND exchange IN (" . $config['exchanges_trade'] . ")"; } - if(!empty($config['pair'])) $sub_query .= " AND pair_asset = '" . $config['pair'] . "'"; + if (!empty($config['pair'])) $sub_query .= " AND pair_asset = '" . $config['pair'] . "'"; $pairs = query($query . $sub_query, $config); - if($config['debug']) var_dump($pairs); - if(empty($pairs)) return FALSE; + if ($config['debug']) var_dump($pairs); + if (empty($pairs)) return FALSE; // for each combination, query the exchange and put result in $transactions $transactions = array(); - foreach($pairs as $pair) { - $config['exchange'] = $pair['exchange']; - $config = config_exchange($config); - $config['pair'] = $pair['pair_asset']; - $result = history_orders($config); - if(!empty($result)) { - // countdim checks the array depth - if(countdim($result) == 1) { - $result['exchange'] = $config['exchange']; - array_push($transactions, $result); - } elseif(countdim($result) > 1) { - foreach ($result as $res) { - $res['exchange'] = $config['exchange']; - array_push($transactions, $res); - } + foreach ($pairs as $pair) { + $config['exchange'] = $pair['exchange']; + $config = config_exchange($config); + $config['pair'] = $pair['pair_asset']; + $result = history_orders($config); + if (!empty($result)) { + // countdim checks the array depth + if (countdim($result) == 1) { + $result['exchange'] = $config['exchange']; + array_push($transactions, $result); + } elseif (countdim($result) > 1) { + foreach ($result as $res) { + $res['exchange'] = $config['exchange']; + array_push($transactions, $res); } } - // pause to limit number of requests to exchange per second - sleep(0.2); + } + // pause to limit number of requests to exchange per second + sleep(0.2); } - if(empty($transactions)) return FALSE; + if (empty($transactions)) return FALSE; $query = "SELECT * FROM transactions"; # whole records - $existing = query($query . $sub_query, $config); + $existing = query($query . $sub_query, $config); foreach ($transactions as $t) { - - if($t['exchange'] == 'bitmax') { - if(!empty($t['data'])) { + if ($t['exchange'] == 'bitmax') { + if (!empty($t['data'])) { process_transaction($config, $existing, $t['data']); } } - - if($t['exchange'] == 'okex') { - if(!empty($t)) { + if ($t['exchange'] == 'okex') { + if (!empty($t)) { process_transaction($config, $existing, $t); } } - } + } /* transform transaction data from exchange and save in database */ -function process_transaction($config, $existing, $order){ - - /* map order id only, not other order details - note that $order_id_only = TRUE */ - $order = map_transaction('', $order, $config, TRUE); - - /* if transaction exists in database, use existing record */ - $exists = FALSE; - if(!empty($existing)) foreach ($existing as $exist) { - if ($exist['exchange_transaction_id'] == $order['exchange_transaction_id'] - && $exist['exchange'] == $order['exchange'] - ) { - $exists = TRUE; - $values = $exist; - echo 'existing transaction' . PHP_EOL; - } +function process_transaction($config, $existing, $order) { + + // map order id only, not other order details + // note that $order_id_only = TRUE + $order = map_transaction('', $order, $config, TRUE); + + // if transaction exists in database, use existing record + $exists = FALSE; + if (!empty($existing)) + foreach ($existing as $exist) { + if ( + $exist['exchange_transaction_id'] == $order['exchange_transaction_id'] + && $exist['exchange'] == $order['exchange'] + ) { + $exists = TRUE; + $values = $exist; + echo 'existing transaction' . PHP_EOL; } + } - /* if transaction not exists in database, create new entry with default values */ - if(!$exists) { - $values = $config['transaction']; - $values['purpose'] = 'trade'; - $values['exchange'] = $config['exchange']; - echo 'new transaction' . PHP_EOL; - } + // if transaction not exists in database, create new entry with default values + if (!$exists) { + $values = $config['transaction']; + $values['purpose'] = 'trade'; + $values['exchange'] = $config['exchange']; + echo 'new transaction' . PHP_EOL; + } - /* map exchange data array */ - $values = map_transaction($values, $order, $config, FALSE); + /* map exchange data array */ + $values = map_transaction($values, $order, $config, FALSE); - query('update_transaction', $config, $values); + query('update_transaction', $config, $values); } @@ -180,17 +201,15 @@ function process_transaction($config, $existing, $order){ function map_transaction($values, $order, $config, $order_id_only = FALSE) { switch ($order['exchange']) { - case 'bitmax': $order['exchange_transaction_id'] = $order['orderId']; - break; + break; case 'okex': $order['exchange_transaction_id'] = $order['order_id']; - break; - + break; } - if($order_id_only) return $order; + if ($order_id_only) return $order; $time = NULL; $status = NULL; @@ -206,27 +225,26 @@ function map_transaction($values, $order, $config, $order_id_only = FALSE) { switch ($order['exchange']) { case 'bitmax': - $time = $order['lastExecTime']; switch($order['status']) { case 'Filled': $status = 'filled'; $values['time_closed'] = $time; - break; + break; case 'New': case 'PartiallyFilled': $status = 'open'; $values['time_opened'] = $time; - break; + break; case 'PendingNew': $status = 'pending_trigger'; $values['time_opened'] = $time; - break; + break; case 'Canceled': # (server typo spelled Canceled) case 'Reject': $status = 'cancelled'; $values['time_closed'] = $time; - break; + break; } $pair_price = $order['price']; $symbol = $order['symbol']; @@ -236,33 +254,31 @@ function map_transaction($values, $order, $config, $order_id_only = FALSE) { $fee = $order['cumFee']; $fee_asset = $order['feeAsset']; $direction = $order['side']; - break; case 'okex': - switch($order['state']) { case '2': # Fully Filled $status = 'filled'; - break; + break; case '0': # Open case '1': # Partially Filled $status = 'open'; - break; + break; case '3': # Submitting case '4': # Canceling $status = 'unconfirmed'; - break; + break; case '-1': # Canceled case '-2': # Failed $status = 'cancelled'; - break; + break; } $values['time_opened'] = strtotime($order['created_at']); #$values['time_closed'] = strtotime($order['timestamp']); $pair_price = $order['price_avg']; $symbol = str_replace('-', '/', $order['instrument_id']); - if($order['type'] == 'limit') { + if ($order['type'] == 'limit') { $quantity = $order['size']; $filled = $order['filled_size']; } elseif ($order['type'] == 'market') { @@ -273,31 +289,30 @@ function map_transaction($values, $order, $config, $order_id_only = FALSE) { $fee = ABS($order['fee']); $fee_asset = $order['fee_currency']; $direction = $order['side']; - break; - } + } /* order filled */ - if($status == 'filled') { - $values['exchange_transaction_status'] = 'complete'; + if ($status == 'filled') { + $values['exchange_transaction_status'] = 'complete'; } /* order open */ - if($status == 'open') { - $values['exchange_transaction_status'] = 'open'; - $values['pair_price'] = $pair_price; + if ($status == 'open') { + $values['exchange_transaction_status'] = 'open'; + $values['pair_price'] = $pair_price; } /* order open, but pending trigger */ - if($status == 'pending_trigger') { - $values['exchange_transaction_status'] = 'trigger open'; - $values['pair_price'] = $pair_price; + if ($status == 'pending_trigger') { + $values['exchange_transaction_status'] = 'trigger open'; + $values['pair_price'] = $pair_price; } /* order cancelled */ - if($status == 'cancelled') { - $values['exchange_transaction_status'] = 'cancelled'; + if ($status == 'cancelled') { + $values['exchange_transaction_status'] = 'cancelled'; } /* simple order information */ @@ -309,48 +324,48 @@ function map_transaction($values, $order, $config, $order_id_only = FALSE) { /* read amounts */ $values['percent_complete'] = round(100 * $filled / $quantity, 0); - if($filled > 0) { - $price = $avg_price; + if ($filled > 0) { + $price = $avg_price; } else { - $price = $pair_price; + $price = $pair_price; } /* sell order */ - if(strtolower($direction) == 'sell') { - $values['from_asset'] = $pair[0]; - $values['from_amount'] = $quantity; - $values['to_asset'] = $pair[1]; - $values['to_amount'] = $price * $quantity; - if($fee_asset == $pair[1]) { - $values['to_fee'] = $fee; - } else { - $values['to_fee'] = $fee * $price; - } - $values['pair_price'] = $values['to_amount'] / $values['from_amount']; - if(in_array($pair[1], array('USDT','USD','USDC','DAI'))) { - $values['from_price_usd'] = $values['to_amount'] / $values['from_amount']; - $values['to_price_usd'] = 1; - $values['price_reference'] = $order['exchange']; - } + if (strtolower($direction) == 'sell') { + $values['from_asset'] = $pair[0]; + $values['from_amount'] = $quantity; + $values['to_asset'] = $pair[1]; + $values['to_amount'] = $price * $quantity; + if ($fee_asset == $pair[1]) { + $values['to_fee'] = $fee; + } else { + $values['to_fee'] = $fee * $price; + } + $values['pair_price'] = $values['to_amount'] / $values['from_amount']; + if (in_array($pair[1], array('USDT','USD','USDC','DAI'))) { + $values['from_price_usd'] = $values['to_amount'] / $values['from_amount']; + $values['to_price_usd'] = 1; + $values['price_reference'] = $order['exchange']; + } } /* buy order */ - if(strtolower($direction) == 'buy') { - $values['from_asset'] = $pair[1]; - $values['from_amount'] = $price * $quantity; - $values['to_asset'] = $pair[0]; - $values['to_amount'] = $quantity; - if($fee_asset == $pair[0]) { - $values['to_fee'] = $fee; - } else { - $values['to_fee'] = $fee / $price; - } - $values['pair_price'] = $values['from_amount'] / $values['to_amount']; - if(in_array($pair[1], array('USDT','USD','USDC','DAI'))) { - $values['from_price_usd'] = 1; - $values['to_price_usd'] = $values['from_amount'] / $values['to_amount']; - $values['price_reference'] = $order['exchange']; - } + if (strtolower($direction) == 'buy') { + $values['from_asset'] = $pair[1]; + $values['from_amount'] = $price * $quantity; + $values['to_asset'] = $pair[0]; + $values['to_amount'] = $quantity; + if ($fee_asset == $pair[0]) { + $values['to_fee'] = $fee; + } else { + $values['to_fee'] = $fee / $price; + } + $values['pair_price'] = $values['from_amount'] / $values['to_amount']; + if (in_array($pair[1], array('USDT','USD','USDC','DAI'))) { + $values['from_price_usd'] = 1; + $values['to_price_usd'] = $values['from_amount'] / $values['to_amount']; + $values['price_reference'] = $order['exchange']; + } } return $values; @@ -361,36 +376,49 @@ function map_transaction($values, $order, $config, $order_id_only = FALSE) { function calculate_orders($config) { - $query = "SELECT a.transaction_id, b.close AS price_aud_usd, 'https://twelvedata.com/' AS aud_usd_reference - FROM transactions a - CROSS JOIN price_history b - INNER JOIN ( - SELECT a.transaction_id, MIN(ABS(a.time_closed - b.timestamp)) AS min_abs_value - FROM transactions a - CROSS JOIN price_history b - WHERE a.price_aud_usd = 0 - AND a.exchange_transaction_status = 'complete' - AND b.pair = 'AUD/USD' - GROUP BY a.transaction_id - ) t - ON a.transaction_id = t.transaction_id - AND ABS(a.time_closed - b.timestamp) = t.min_abs_value - WHERE a.price_aud_usd = 0 - AND a.exchange_transaction_status = 'complete' - AND b.pair = 'AUD/USD' - "; + $query = " + SELECT + a.transaction_id, + b.close AS price_aud_usd, + 'https://twelvedata.com/' AS aud_usd_reference + FROM transactions a + CROSS JOIN price_history b + INNER JOIN ( + SELECT + a.transaction_id, + MIN(ABS(a.time_closed - b.timestamp)) AS min_abs_value + FROM transactions a + CROSS JOIN price_history b + WHERE a.price_aud_usd = 0 + AND a.exchange_transaction_status = 'complete' + AND b.pair = 'AUD/USD' + GROUP BY a.transaction_id + ) t + ON a.transaction_id = t.transaction_id + AND ABS(a.time_closed - b.timestamp) = t.min_abs_value + WHERE a.price_aud_usd = 0 + AND a.exchange_transaction_status = 'complete' + AND b.pair = 'AUD/USD' + "; $orders = query($query, $config); - foreach($orders as $order) { - $query = "UPDATE transactions SET price_aud_usd = " . $order['price_aud_usd'] . ", aud_usd_reference = '" . $order['aud_usd_reference'] . "' WHERE transaction_id = " . $order['transaction_id']; + foreach ($orders as $order) { + $query = " + UPDATE transactions + SET price_aud_usd = " . $order['price_aud_usd'] . ", + aud_usd_reference = '" . $order['aud_usd_reference'] . "' + WHERE transaction_id = " . $order['transaction_id'] + ; query($query, $config); } # capital estimate - $query = "UPDATE transactions SET - fee_amount_usd = to_fee * to_price_usd, - capital_amount = to_amount * to_price_usd / price_aud_usd, - capital_fee = fee_amount_usd / price_aud_usd - WHERE exchange_transaction_status = 'complete' - "; + $query = " + UPDATE transactions SET + fee_amount_usd = to_fee * to_price_usd, + capital_amount = to_amount * to_price_usd / price_aud_usd, + capital_fee = fee_amount_usd / price_aud_usd + WHERE exchange_transaction_status = 'complete' + "; query($query, $config); + } diff --git a/functions.order.php b/functions.order.php index 17d8ce8..c225288 100644 --- a/functions.order.php +++ b/functions.order.php @@ -1,16 +1,16 @@ call($httpheader, $config['method'], $order); + $class = new APIREST($config['url']); + $result = $class -> call($httpheader, $config['method'], $order); - return json_decode($result, TRUE); + return json_decode($result, TRUE); } @@ -18,7 +18,11 @@ function order($config, $order) { function place_order($config, $order_query, $orderId = '') { - if(isset($order_query['orderId'])) { $orderId = $order_query['orderId']; } else { $orderId = ''; } + if (isset($order_query['orderId'])) { + $orderId = $order_query['orderId']; + } else { + $orderId = ''; + } $order = array(); @@ -26,79 +30,91 @@ function place_order($config, $order_query, $orderId = '') { case 'bitmax': $config['api_request'] = 'order'; - $config['url'] .= $config['group'] . $config['order']; - $config['method'] = 'POST'; - $order['id'] = 'a' . # a for order via rest api - dechex($config['timestamp']) . # convert timestamp to hex - $config['user_id'] . # user id - $orderId; # order num with 9 characters/numbers, ending with a character - # self-generated order id by choice, or provided if empty - #if(strlen($order['id']) !== 32) die; + $config['url'] .= $config['group'] . $config['order']; + $config['method'] = 'POST'; + $order['id'] = + 'a' . # a for order via rest api + dechex($config['timestamp']) . # convert timestamp to hex + $config['user_id'] . # user id + $orderId # order num 9 characters/numbers, ending with a character, system-generated if empty + ; + if (strlen($order['id']) !== 32) { + $config['chatText'] = 'incorrect order id for bitmax'; + telegram($config); + die; + } $order['time'] = (int)$config['timestamp']; - $order['symbol'] = $order_query['symbol']; - $order['orderPrice'] = $order_query['orderPrice']; - $order['orderQty'] = $order_query['orderQty']; - $order['orderType'] = $order_query['orderType']; # market, limit, stop_market, stop_limit - $order['side'] = $order_query['side']; # buy, sell - $order['respInst'] = $order_query['respInst']; # ACK, ACCEPT, DONE - - break; + $order['symbol'] = $order_query['symbol']; + $order['orderPrice'] = $order_query['orderPrice']; + $order['orderQty'] = $order_query['orderQty']; + $order['orderType'] = $order_query['orderType']; # market, limit, stop_market, stop_limit + $order['side'] = $order_query['side']; # buy, sell + $order['respInst'] = $order_query['respInst']; # ACK, ACCEPT, DONE + break; + case 'okex': $order['type'] = $order_query['orderType']; # limit or market. When placing market orders, order_type must be 0 $order['side'] = $order_query['side']; # buy or sell $order['instrument_id'] = str_replace('/', '-', $order_query['symbol']); - if($orderId !== '') $order['client_oid'] = $orderId; # between 1-32 characters - if($order['type'] == 'limit') { + if ($orderId !== '') $order['client_oid'] = $orderId; # between 1-32 characters + if ($order['type'] == 'limit') { $order['size'] = $order_query['orderQty']; $order['price'] = $order_query['orderPrice']; - if(!empty($order_query['orderTypeCode'])) $order['order_type'] = $order_query['orderTypeCode']; # 0: Normal order (Unfilled and 0 imply normal limit order) 1: Post only 2: Fill or Kill 3: Immediate Or Cancel + if (!empty($order_query['orderTypeCode'])) + # 0: Normal order (Unfilled and 0 imply normal limit order) + # 1: Post only + # 2: Fill or Kill + # 3: Immediate Or Cancel + $order['order_type'] = $order_query['orderTypeCode']; } - if($order['type'] == 'market') { - if($order['side'] == 'buy') $order['notional'] = $order_query['orderQty']; - else $order['size'] = $order_query['orderQty']; + if ($order['type'] == 'market') { + if ($order['side'] == 'buy') { + $order['notional'] = $order_query['orderQty']; + } else { + $order['size'] = $order_query['orderQty']; + } #$order['order_type'] = '0'; } $config['method'] = 'POST'; $config['api_request'] = $config['order'] . json_encode($order, JSON_UNESCAPED_SLASHES); $config['url'] .= $config['order']; - break; + break; } - if($config['debug']) { echo $config['url'] . PHP_EOL; echo $config['api_request'] . PHP_EOL; } + if ($config['debug']) echo $config['url'] . PHP_EOL . $config['api_request'] . PHP_EOL; - $res = order($config, $order); - if($config['debug']) print_r($res); - $result = array('res' => array( - 'placed' => FALSE, - 'code' => '', - 'message' => '', - 'exchange_transaction_id' => '' - ), - 'query' => $order); + $res = order($config, $order); + if ($config['debug']) print_r($res); + $result = array( + 'res' => array( + 'placed' => FALSE, + 'code' => '', + 'message' => '', + 'exchange_transaction_id' => '' + ), + 'query' => $order + ); switch($config['exchange']) { - case 'bitmax': $result['res']['code'] = $res['code']; - if($res['code'] == 0) { + if ($res['code'] == 0) { $result['res']['placed'] = TRUE; $result['res']['exchange_transaction_id'] = $res['info']['id']; } else { $result['res']['message'] = $res['reason'] . ' ' . $res['message']; } - break; - + break; case 'okex': $result['res']['code'] = $res['error_code']; - if($res['error_code'] == 0) { + if ($res['error_code'] == 0) { $result['res']['placed'] = TRUE; $result['res']['exchange_transaction_id'] = $res['order_id']; } else { $result['res']['message'] = $res['error_message']; } - break; - + break; } return $result; @@ -111,58 +127,54 @@ function cancel_order($config, $order_query) { $order = array(); switch($config['exchange']) { - case 'bitmax': $order['orderId'] = $order_query['orderId']; $order['symbol'] = $order_query['symbol']; $order['time'] = (int)$config['timestamp']; $config['api_request'] = 'order'; - $config['url'] .= $config['group'] . $config['order']; - $config['method'] = 'DELETE'; - break; - + $config['url'] .= $config['group'] . $config['order']; + $config['method'] = 'DELETE'; + break; case 'okex': $config['method'] = 'POST'; $order['instrument_id'] = str_replace('/', '-', $order_query['symbol']); $config['api_request'] = $config['delete'] . $order_query['orderId']; $config['url'] .= $config['api_request']; $config['api_request'] .= json_encode($order, JSON_UNESCAPED_SLASHES); - break; - + break; } $res = order($config, $order); - if($config['debug']) print_r($res); - $result = array('res' => array( - 'placed' => FALSE, - 'code' => '', - 'message' => '', - 'exchange_transaction_id' => '' - ), - 'query' => $order); + if ($config['debug']) print_r($res); + $result = array( + 'res' => array( + 'placed' => FALSE, + 'code' => '', + 'message' => '', + 'exchange_transaction_id' => '' + ), + 'query' => $order + ); switch($config['exchange']) { - case 'bitmax': $result['res']['code'] = $res['code']; - if($res['code'] == 0) { + if ($res['code'] == 0) { $result['res']['placed'] = TRUE; } else { $result['res']['message'] = $res['reason'] . ' ' . $res['message']; } - break; - + break; case 'okex': $result['res']['code'] = $res['error_code']; - if($res['error_code'] == 0) { + if ($res['error_code'] == 0) { $result['res']['placed'] = TRUE; } else { $result['res']['message'] = $res['error_message']; } - break; - + break; } - return $result; + return $result; } diff --git a/functions.php b/functions.php index 145a33d..0d1d048 100644 --- a/functions.php +++ b/functions.php @@ -4,98 +4,111 @@ function info($config) { - $httpheader = http_headers($config); - #var_dump($httpheader); - $class = new APIREST($config['url']); - $result = $class -> call($httpheader, $config['method']); + $httpheader = http_headers($config); - return json_decode($result, TRUE); + $class = new APIREST($config['url']); + $result = $class -> call($httpheader, $config['method']); + + return json_decode($result, TRUE); } /* send notification message to telegram bot */ function telegram($config) { - /* bot name: univert + /* - show chat id (needs webhook disabled): - https://api.telegram.org/bot0000000000:xxx_API_KEY_xxx/getUpdates + show chat id (needs webhook disabled): + https://api.telegram.org/bot0000000000:xxx_API_KEY_xxx/getUpdates - Use $config['chatPath'] the HTTP API: + Use $config['chatPath'] the HTTP API: - For a description of the Bot API, see this page: https://core.telegram.org/bots/api + For a description of the Bot API, see this page: https://core.telegram.org/bots/api - for interactive bot - example: https://nordicapis.com/how-to-build-your-first-telegram-bot-using-php-in-under-30-minutes/ + for interactive bot + example: https://nordicapis.com/how-to-build-your-first-telegram-bot-using-php-in-under-30-minutes/ - activate webhook: - https://api.telegram.org/bot0000000000:xxx_API_KEY_xxx/setwebhook?url=https://your.server.com/telegram.php + activate webhook: + https://api.telegram.org/bot0000000000:xxx_API_KEY_xxx/setwebhook?url=https://your.server.com/telegram.php - deactivate webhook: - https://api.telegram.org/bot0000000000:xxx_API_KEY_xxx/setwebhook?url= + deactivate webhook: + https://api.telegram.org/bot0000000000:xxx_API_KEY_xxx/setwebhook?url= - */ + */ - $httpheader = http_headers($config, TRUE); - $query = $config['chatPath'] . '/sendmessage?chat_id=' . $config['chatId'] . '&parse_mode=html&text=' . $config['chatText']; + $httpheader = http_headers($config, TRUE); + $query = + $config['chatPath'] . + '/sendmessage?chat_id=' . $config['chatId'] . + '&parse_mode=html&text=' . $config['chatText'] + ; - $class = new APIREST($query); - $result = $class -> call($httpheader, $config['method']); + $class = new APIREST($query); + $result = $class -> call($httpheader, $config['method']); - return json_decode($result, TRUE); + return json_decode($result, TRUE); } /* define http headers and parameters for exchange API */ function http_headers($config, $default = FALSE) { - if($default) { + if ($default) { + $httpheader = array( - 'Accept: ' . $config['accept'], - 'Content-Type: ' . $config['content_type'] - ); + 'Accept: ' . $config['accept'], + 'Content-Type: ' . $config['content_type'] + ); + } else { - switch ($config['exchange']) { + switch ($config['exchange']) { case 'bitmax': - $config['msg'] = $config['timestamp'] . '+' . $config['api_request']; - $config['signature'] = hmac($config['msg'], $config['secret']); - $httpheader = array( - 'Accept: ' . $config['accept'], - 'Content-Type: ' . $config['content_type'], - 'x-auth-key: ' . $config['api_key'], - 'x-auth-signature: ' . $config['signature'], - 'x-auth-timestamp: ' . $config['timestamp'] - ); - break; + $config['msg'] = + $config['timestamp'] . + '+' . + $config['api_request'] + ; + $config['signature'] = hmac($config['msg'], $config['secret']); + $httpheader = array( + 'Accept: ' . $config['accept'], + 'Content-Type: ' . $config['content_type'], + 'x-auth-key: ' . $config['api_key'], + 'x-auth-signature: ' . $config['signature'], + 'x-auth-timestamp: ' . $config['timestamp'] + ); + break; case 'okex': - #$timestamp = date('Y-m-d\TH:i:s.000', $config['timestamp'] / 1000) . 'Z'; # ISO 8601 standard format with Z - $config['msg'] = (string) $config['timestamp'] . $config['method'] . $config['api_request']; - $config['signature'] = hmac($config['msg'], $config['secret']); - $httpheader = array( - 'Accept: ' . $config['accept'], - 'Content-Type: ' . $config['content_type'], - 'ok-access-key: ' . $config['api_key'], - 'ok-access-sign: ' . $config['signature'], - 'ok-access-timestamp: ' . $config['timestamp'] / 1000, - 'ok-access-passphrase: ' . $config['pass'] - #'OK-TEXT-TO-SIGN: ' . $config['msg'] - ); - break; + #$timestamp = date('Y-m-d\TH:i:s.000', $config['timestamp'] / 1000) . 'Z'; # ISO 8601 standard format with Z + $config['msg'] = + (string) $config['timestamp'] . + $config['method'] . + $config['api_request'] + ; + $config['signature'] = hmac($config['msg'], $config['secret']); + $httpheader = array( + 'Accept: ' . $config['accept'], + 'Content-Type: ' . $config['content_type'], + 'ok-access-key: ' . $config['api_key'], + 'ok-access-sign: ' . $config['signature'], + 'ok-access-timestamp: ' . $config['timestamp'] / 1000, + 'ok-access-passphrase: ' . $config['pass'] + #'OK-TEXT-TO-SIGN: ' . $config['msg'] + ); + break; default: $httpheader = array( - 'Accept: ' . $config['accept'], - 'Content-Type: ' . $config['content_type'] - ); + 'Accept: ' . $config['accept'], + 'Content-Type: ' . $config['content_type'] + ); - } + } } - #if(isset($config['get_param'])) array_push($httpheader, $config['get_param']); - return $httpheader; + return $httpheader; } diff --git a/functions.price.php b/functions.price.php index f782b0f..adf050c 100644 --- a/functions.price.php +++ b/functions.price.php @@ -7,25 +7,37 @@ function price_query($config, $pq) { # make query string switch ($config['exchange']) { case 'twelve': - $config['price_history'] = $config['url'] . $config['price_history'] . '?symbol=' . $pq['pair'] . '&apikey=' . $config['api_key'] - . '&interval=' . $config['period_exchange'][$pq['period']] . '&outputsize=' . $pq['obs_iter'] . '&format=JSON&timezone=UTC'; - break; + $config['price_history'] = + $config['url'] . + $config['price_history'] . + '?symbol=' . $pq['pair'] . + '&apikey=' . $config['api_key'] . + '&interval=' . $config['period_exchange'][$pq['period']] . + '&outputsize=' . $pq['obs_iter'] . + '&format=JSON&timezone=UTC' + ; + break; case 'bitmax': $config['api_request'] = 'barhist'; - $config['price_history'] = $config['url'] . $config['price_history'] . '?symbol=' . $pq['pair'] . '&n=' . $pq['obs_iter']; - $config['price_history'] .= '&interval=' . $config['period_exchange'][$pq['period']]; - break; + $config['price_history'] = + $config['url'] . + $config['price_history'] . + '?symbol=' . $pq['pair'] . + '&n=' . $pq['obs_iter'] . + '&interval=' . $config['period_exchange'][$pq['period']] + ; + break; case 'okex': $config['price_history'] .= str_replace('/', '-', $pq['pair']); - if($pq['hist_long']) $config['price_history'] .= '/history'; + if ($pq['hist_long']) $config['price_history'] .= '/history'; $config['price_history'] = $config['url'] . $config['price_history']; - break; + break; } - # set start time; stop at current time; add number of periods minutes; + # set start time; stop at current time; add number of periods minutes; $j = ($pq['period_ms'] * $pq['obs_iter']); $i = ceil(($pq['stop'] - $pq['start']) / $j); - if($i > 1) { + if ($i > 1) { $to = $pq['start'] + $j - $pq['period_ms']; # we need 1 period less than the maximum for looping } else { $i = 1; # in case $i = 0 @@ -35,119 +47,150 @@ function price_query($config, $pq) { $from = $pq['start']; # split the query into separate API requests if the number of records exceeds the maximum allowed - for ($i; $i > 0; $i--) { - - echo '$from: ' . $from . ' $to: ' . $to . ' units: ' . floor(($to - $from) / $pq['period_ms']) . ' of ' . floor(($pq['stop'] - $pq['obs_iter']) / $pq['period_ms']) . PHP_EOL; - echo '$i: ' . $i . ' $j: ' . $j . ' $period_ms: ' . $pq['period_ms'] . PHP_EOL; - - # create the API request string - switch ($config['exchange']) { - case 'twelve': - $config['url'] = $config['price_history'] . '&start_date=' . date('Y-m-d H:i:s', $from / 1000) . '&end_date=' . date('Y-m-d H:i:s', $to / 1000); - $config['url'] = str_replace(' ', ' ', $config['url']); - break; - case 'bitmax': - $config['url'] = $config['price_history'] . '&from=' . $from . '&to=' . $to; - break; - case 'okex': - if($pq['hist_long']) $config['api_request'] = '/candles' - # okex dates in reverse order for /history - # seems like a bug in their code - . '?start=' . date('Y-m-d\TH:i:s.000', $to / 1000) . 'Z' - . '&end=' . date('Y-m-d\TH:i:s.000', $from / 1000) . 'Z' - . '&granularity=' . $config['period_exchange'][$pq['period']]; - else $config['api_request'] = '/candles' - . '?granularity=' . $config['period_exchange'][$pq['period']] - # okex dates in normal order for not /history - . '&start=' . date('Y-m-d\TH:i:s.000', $from / 1000) . 'Z' - . '&end=' . date('Y-m-d\TH:i:s.000', $to / 1000) . 'Z'; - $config['url'] = $config['price_history'] . $config['api_request']; - break; - } + for ($i; $i > 0; $i--) { + + echo + '$from: ' . $from . + ' $to: ' . $to . + ' units: ' . floor(($to - $from) / $pq['period_ms']) . + ' of ' . floor(($pq['stop'] - $pq['obs_iter']) / $pq['period_ms']) . + PHP_EOL + ; + echo + '$i: ' . $i . + ' $j: ' . $j . + ' $period_ms: ' . $pq['period_ms'] . + PHP_EOL + ; + + # create the API request string + switch ($config['exchange']) { + + case 'twelve': + $config['url'] = + $config['price_history'] . + '&start_date=' . date('Y-m-d H:i:s', $from / 1000) . + '&end_date=' . date('Y-m-d H:i:s', $to / 1000) + ; + $config['url'] = str_replace(' ', ' ', $config['url']); + break; + + case 'bitmax': + $config['url'] = + $config['price_history'] . + '&from=' . $from . + '&to=' . $to + ; + break; - echo 'url: ' . $config['url'] . PHP_EOL; + case 'okex': + if ($pq['hist_long']) + $config['api_request'] = + '/candles' . + # okex dates in reverse order for /history + # seems like a bug in their code + '?start=' . date('Y-m-d\TH:i:s.000', $to / 1000) . 'Z' . + '&end=' . date('Y-m-d\TH:i:s.000', $from / 1000) . 'Z' . + '&granularity=' . $config['period_exchange'][$pq['period']] + ; + else + $config['api_request'] = + '/candles' . + '?granularity=' . $config['period_exchange'][$pq['period']] . + # okex dates in normal order for not /history + '&start=' . date('Y-m-d\TH:i:s.000', $from / 1000) . 'Z' . + '&end=' . date('Y-m-d\TH:i:s.000', $to / 1000) . 'Z' + ; + $config['url'] = $config['price_history'] . $config['api_request']; + break; + + } + + echo 'url: ' . $config['url'] . PHP_EOL; - $result = info($config); + $result = info($config); + + # process response + if (!empty($result)) { + + $values = array(); + $values['pair'] = $pq['pair']; + $values['source'] = $config['exchange']; + $values['period'] = $config['period'][$pq['period']]; + $values['imputed'] = 0; + + # read the response in the array format for the exchange + # okex already in correct format + if ($config['exchange'] == 'twelve') { + $values['pair'] = $result['meta']['symbol']; + $result = $result['values']; + } + if ($config['exchange'] == 'bitmax') { + $array = array(); + foreach ($result['data'] as $data) array_push($array, $data['data']); + $result = $array; + } - # process response - if(!empty($result)) { + echo 'result: ' . count((array)$result) . PHP_EOL; + if ($config['debug']) print_r($result); - $values = array(); - $values['pair'] = $pq['pair']; - $values['source'] = $config['exchange']; - $values['period'] = $config['period'][$pq['period']]; - $values['imputed'] = 0; + # process result one row (price bar) at a time because it will be + # easier to check the database if the record already exists using a single row + if (!empty($result)) + foreach ($result as $price) { - # read the response in the array format for the exchange - # okex already in correct format if ($config['exchange'] == 'twelve') { - $values['pair'] = $result['meta']['symbol']; - $result = $result['values']; + # server seems to expect requested data on separate dates + $values['timestamp'] = strtotime($price['datetime']) * 1000; # bar start time + $values['open'] = $price['open']; + $values['high'] = $price['high']; + $values['low'] = $price['low']; + $values['close'] = $price['close']; + $values['volume'] = $price['volume']; } + if ($config['exchange'] == 'bitmax') { - $array = array(); - foreach ($result['data'] as $data) array_push($array, $data['data']); - $result = $array; + # possible that server returns missing value for bar + $values['timestamp'] = $price['ts']; # bar start time + $values['open'] = $price['o']; + $values['high'] = $price['h']; + $values['low'] = $price['l']; + $values['close'] = $price['c']; + $values['volume'] = $price['v']; } - echo 'result: ' . count((array)$result) . PHP_EOL; - if($config['debug']) print_r($result); - - # process result one row (price bar) at a time because it will be - # easier to check the database if the record already exists using a single row - if(!empty($result)) - foreach ($result as $price) { - - if ($config['exchange'] == 'twelve') { - # server seems to expect requested data on separate dates - $values['timestamp'] = strtotime($price['datetime']) * 1000; # bar start time - $values['open'] = $price['open']; - $values['high'] = $price['high']; - $values['low'] = $price['low']; - $values['close'] = $price['close']; - $values['volume'] = $price['volume']; - } - - if ($config['exchange'] == 'bitmax') { - # possible that server returns missing value for bar - $values['timestamp'] = $price['ts']; # bar start time - $values['open'] = $price['o']; - $values['high'] = $price['h']; - $values['low'] = $price['l']; - $values['close'] = $price['c']; - $values['volume'] = $price['v']; - } - - if ($config['exchange'] == 'okex') { - $values['pair'] = str_replace('-', '/', $values['pair']); - $values['timestamp'] = strtotime($price[0]) * 1000; # convert to unix time - $values['open'] = $price[1]; - $values['high'] = $price[2]; - $values['low'] = $price[3]; - $values['close'] = $price[4]; - $values['volume'] = $price[5]; - } - - # save row - query('update_history', $config, $values); - #var_dump($values);break 2; - # option to skip deduplication within iteration - # would still need to call price_history_dedupe after all iterations - # not currently used, but could be for performance improvement - if(!$pq['dedupe_hist']) continue 1; - # check if duplicate price history record and remove oldest ones - $values['filterquery'] = "AND a.pair = '" . $values['pair'] . "' - AND a.source = '" . $values['source'] . "' - AND a.timestamp = " . $values['timestamp'] . " - AND a.period = '" . $values['period'] . "'"; - query('deduplicate_history', $config, $values); + if ($config['exchange'] == 'okex') { + $values['pair'] = str_replace('-', '/', $values['pair']); + $values['timestamp'] = strtotime($price[0]) * 1000; # convert to unix time + $values['open'] = $price[1]; + $values['high'] = $price[2]; + $values['low'] = $price[3]; + $values['close'] = $price[4]; + $values['volume'] = $price[5]; } + + # save row + query('update_history', $config, $values); + #var_dump($values);break 2; + # option to skip deduplication within iteration + # would still need to call price_history_dedupe after all iterations + # not currently used, but could be for performance improvement + if (!$pq['dedupe_hist']) continue 1; + # check if duplicate price history record and remove oldest ones + $values['filterquery'] = " + AND a.pair = '" . $values['pair'] . "' + AND a.source = '" . $values['source'] . "' + AND a.timestamp = " . $values['timestamp'] . " + AND a.period = '" . $values['period'] . "' + "; + query('deduplicate_history', $config, $values); } + } - $from += $j; - $to += $j; - sleep(0.2); # use delay to reduce server load - } + $from += $j; + $to += $j; + sleep(0.2); # use delay to reduce server load + } } /* check for all possible duplicate price history record and remove oldest ones */ @@ -155,45 +198,67 @@ function price_query($config, $pq) { function price_history_dedupe($config) { # quick check if all records are unique - $total = query('SELECT COUNT(*) AS count FROM `price_history`', $config); - $dedupes = query('SELECT COUNT(DISTINCT - `pair`, - `source`, - `timestamp`, - `period` - ) AS count - FROM `price_history` - ', $config); + $query_all = " + SELECT COUNT(*) AS count FROM `price_history` + "; + $total = query($query_all, $config); + $query_dis = " + SELECT COUNT( + DISTINCT + `pair`, + `source`, + `timestamp`, + `period` + ) AS count + FROM `price_history` + "; + $dedupes = query($query_dis, $config); $dupes = $total[0]['count'] - $dedupes[0]['count']; echo $dupes . ' duplicates' . PHP_EOL; - if(!$dupes) return; + if (!$dupes) return; echo 'deduplicating ...'; # list all possible asset pairs and periods - $permutations = query('SELECT DISTINCT - `pair`, - `source`, - `period` - FROM `price_history` - ', $config); + $query_pair = " + SELECT DISTINCT + `pair`, + `source`, + `period` + FROM `price_history` + "; + $permutations = query($query_pair, $config); # process each possible pair + $query_ded = " + SELECT DISTINCT + `pair`, + `source`, + `timestamp`, + `period` + FROM `price_history` + "; foreach ($permutations as $p) { - $filter = "WHERE pair = '" . $p['pair'] . "' AND source = '" . $p['source'] . "' AND period = '" . $p['period'] . "'"; - $total = query("SELECT COUNT(*) AS count FROM `price_history` " . $filter, $config); - $dedupes = query("SELECT DISTINCT `pair`, `source`, `timestamp`, `period` FROM `price_history`" . $filter, $config); + $filter = " + WHERE pair = '" . $p['pair'] . "' + AND source = '" . $p['source'] . "' + AND period = '" . $p['period'] . "' + "; + $total = query($query_all . $filter, $config); + $dedupes = query($query_ded . $filter, $config); $dupes = $total[0]['count'] - count($dedupes); - if(!$dupes) continue 1; - echo $dupes . ' ' . $filter . PHP_EOL; + if (!$dupes) continue 1; + echo $dupes . ' dupes ' . $filter . PHP_EOL; foreach ($dedupes as $record) { - $values['filterquery'] = "AND a.pair = '" . $record['pair'] . "' - AND a.source = '" . $record['source'] . "' - AND a.timestamp = " . $record['timestamp'] . " - AND a.period = '" . $record['period'] . "'"; + $values['filterquery'] = " + AND a.pair = '" . $record['pair'] . "' + AND a.source = '" . $record['source'] . "' + AND a.timestamp = " . $record['timestamp'] . " + AND a.period = '" . $record['period'] . "' + "; query('deduplicate_history', $config, $values); } } @@ -204,30 +269,54 @@ function price_history_dedupe($config) { function price_history_trim($config) { # get all asset pairs - $query = "SELECT DISTINCT pair, source, period FROM asset_pairs"; + $query = " + SELECT DISTINCT + pair, + source, + period + FROM asset_pairs + "; $history = query($query, $config); # get history_id without asset pairs $query = "SELECT history_id FROM price_history WHERE 1=1"; foreach ($history as $hist) { - if($config['debug']) foreach($hist as $key => $val) { - echo $key . ': ' . $val . ' '; - } + if ($config['debug']) + foreach ($hist as $key => $val) { + echo $key . ': ' . $val . ' '; + } echo PHP_EOL; - $query .= " AND (pair != '" . $hist['pair'] . "' AND source != '" . $hist['source'] . "' AND period != '" . $hist['period'] . "')"; + $query .= " + AND ( + pair != '" . $hist['pair'] . "' + AND source != '" . $hist['source'] . "' + AND period != '" . $hist['period'] . "' + ) + "; } $drop_ids = query($query, $config); # delete those history_id if any echo PHP_EOL; - if(!empty($drop_ids)) { - $query = "FROM price_history WHERE history_id IN (0"; - foreach ($drop_ids as $array) $query .= ", " . $array['history_id']; - $query .= ")"; - $result = query("SELECT DISTINCT pair, source, period " . $query, $config); + if (!empty($drop_ids)) { + $filter = " + FROM price_history + WHERE history_id + IN (0 + "; + foreach ($drop_ids as $array) $filter .= ", " . $array['history_id']; + $filter .= ")"; + $query = " + SELECT DISTINCT + pair, + source, + period + "; + $result = query($query . $filter, $config); echo 'deleting history_id without asset pairs: ' . PHP_EOL; var_dump($result); - query("DELETE " . $query, $config); + $query = "DELETE "; + query($query . $filter, $config); } else { echo 'no history_id without asset pairs'; } @@ -240,34 +329,42 @@ function history_currency($config, $query, $pq) { $history = query($query, $config); $count = count($history); - $currency = $history[$count-1]['timestamp']; + $currency = $history[$count - 1]['timestamp']; $hist = array(); - if(!empty($history)) { + if (!empty($history)) { foreach ($history as $array) { array_push($hist, $array['timestamp']); } for ($i = 1; $i < $count; $i++) { - if($hist[$i] - $hist[$i-1] !== $pq['period_ms']) { + if ($hist[$i] - $hist[$i - 1] !== $pq['period_ms']) { # expect some asset pairs are not recorded on weekends - if(!$pq['weekends']) { + if (!$pq['weekends']) { $missing = 0; - for ($j = $hist[$i-1] + $pq['period_ms']; $j < $hist[$i]; $j += $pq['period_ms']) { + for ( + $j = $hist[$i - 1] + $pq['period_ms']; + $j < $hist[$i]; + $j += $pq['period_ms'] + ) { $day = date('l', $j / 1000); - if(!($day == 'Sunday' || $day == 'Monday')) $missing++; + if (!($day == 'Sunday' || $day == 'Monday')) $missing++; } - if(!$missing) continue 1; + if (!$missing) continue 1; } else { - $currency = $hist[$i-1]; + $currency = $hist[$i - 1]; break 1; } } } } echo '$currency: UTC ' . date('Y-m-d H:i:s', $currency / 1000) . PHP_EOL; - $query = "UPDATE asset_pairs SET currency = " . $currency . " WHERE pair_id = " . $pq['pair_id']; + $query = " + UPDATE asset_pairs + SET currency = " . $currency . " + WHERE pair_id = " . $pq['pair_id'] + ; query($query, $config); } @@ -277,19 +374,24 @@ function history_currency($config, $query, $pq) { function price_history($config, $pair_id = FALSE) { # select asset_pairs due for refreshing - $query = "SELECT * FROM asset_pairs - WHERE collect - AND ( - (history_end > " . milliseconds() . " - AND currency < (" . milliseconds() . " - refresh * 60000)) - OR (history_end < " . milliseconds() . " - AND currency < (history_end - period * 60000)) - )"; - if($pair_id) $query .= " AND pair_id = " . $pair_id; + $query = " + SELECT * FROM asset_pairs + WHERE collect + AND ( + ( + history_end > " . milliseconds() . " + AND currency < (" . milliseconds() . " - refresh * 60000) + ) OR ( + history_end < " . milliseconds() . " + AND currency < (history_end - period * 60000) + ) + ) + "; + if ($pair_id) $query .= " AND pair_id = " . $pair_id; $pairs = query($query, $config); # check if any results - if(empty($pairs)) echo 'current'; + if (empty($pairs)) echo 'current'; else # process each result foreach ($pairs as $pair) { @@ -311,52 +413,61 @@ function price_history($config, $pair_id = FALSE) { $pq['stop'] = milliseconds(); # define time parameters - if($pair['history_start'] > $pq['start']) $pq['start'] = $pair['history_start']; - if($pair['history_end'] < $pq['stop']) $pq['stop'] = $pair['history_end']; + if ($pair['history_start'] > $pq['start']) $pq['start'] = $pair['history_start']; + if ($pair['history_end'] < $pq['stop']) $pq['stop'] = $pair['history_end']; # exit if time period incorrect - if($pq['start'] >= $pq['stop']) continue 1; + if ($pq['start'] >= $pq['stop']) continue 1; # ignore weekends for certain asset classes # and set start - 3 days $pq['weekends'] = weekends($pair['class']); - if(!$pq['weekends']) $pq['start'] = $pq['start'] - 1440 * 60000 * 3; + if (!$pq['weekends']) $pq['start'] = $pq['start'] - 1440 * 60000 * 3; # some APIs limit available history for some coins, check if longer history needed switch ($config['exchange']) { case 'okex': - if((milliseconds() - $pq['start']) / $pq['period_ms'] > $config['obs_hist_max']) { + if ((milliseconds() - $pq['start']) / $pq['period_ms'] > $config['obs_hist_max']) { # check if longer history available - if(in_array($pair['pair'], $config['hist_pairs'])) { + if (in_array($pair['pair'], $config['hist_pairs'])) { $pq['hist_long'] = TRUE; } else { - $config['chatText'] = 'requested price history too long for pair_id ' . $pair['pair_id'] . ', you need to manually define earliest query in asset_pairs table'; + $config['chatText'] = + 'requested price history too long for pair_id ' . $pair['pair_id'] . + ', you need to manually define earliest query in asset_pairs table' + ; telegram($config); echo $config['chatText'] . PHP_EOL; continue 2; # continue to next iteration in nearest containing loop (value is +1 when inside 'switch' but not 'if' statement, as of php 7.3) } } - break; + break; } # select recorded timestamps $query_part = " - AND pair = '" . $pair['pair'] . "' - AND source = '" . $pair['source'] . "' - AND period = '" . $config['period'][$pq['period']] . "' - AND timestamp >= " . $pq['start'] . " - AND timestamp <= " . $pq['stop'] . " - ORDER BY timestamp"; - $query = "SELECT timestamp FROM price_history - WHERE (timestamp = (SELECT MIN(timestamp) FROM price_history WHERE 1=1 " . $query_part . ") - OR timestamp = (SELECT MAX(timestamp) FROM price_history WHERE 1=1 " . $query_part . "))"; + AND pair = '" . $pair['pair'] . "' + AND source = '" . $pair['source'] . "' + AND period = '" . $config['period'][$pq['period']] . "' + AND timestamp >= " . $pq['start'] . " + AND timestamp <= " . $pq['stop'] . " + ORDER BY timestamp + "; + $query = " + SELECT timestamp + FROM price_history + WHERE ( + timestamp = (SELECT MIN(timestamp) FROM price_history WHERE 1=1 " . $query_part . ") + OR timestamp = (SELECT MAX(timestamp) FROM price_history WHERE 1=1 " . $query_part . ") + ) + "; $history = query($query . $query_part, $config); $count = count($history); # define query result parameters - if($count <= 1) { + if ($count <= 1) { # handle exception of small result $oldest = milliseconds(); $newest = milliseconds(); @@ -366,15 +477,21 @@ function price_history($config, $pair_id = FALSE) { } # print parameters - if($config['debug']) { - echo 'history_start: ' . date('Y-m-d H:i:s', $pair['history_start'] / 1000) - . ' history_end: ' . date('Y-m-d H:i:s', $pair['history_end'] / 1000) . PHP_EOL; - echo '$count: ' . $count . ' $currency: ' . date('Y-m-d H:i:s', $pq['start'] / 1000) . ' $pq[start]: ' . date('Y-m-d H:i:s', $pq['start'] / 1000) - . ' $oldest: ' . date('Y-m-d H:i:s', $oldest / 1000) . PHP_EOL; + if ($config['debug']) { + echo + 'history_start: ' . date('Y-m-d H:i:s', $pair['history_start'] / 1000) . + ' history_end: ' . date('Y-m-d H:i:s', $pair['history_end'] / 1000) . PHP_EOL + ; + echo + '$count: ' . $count . + ' $currency: ' . date('Y-m-d H:i:s', $pq['start'] / 1000) . + ' $pq[start]: ' . date('Y-m-d H:i:s', $pq['start'] / 1000) . + ' $oldest: ' . date('Y-m-d H:i:s', $oldest / 1000) . PHP_EOL + ; } # check if the earliest required record is in the database, and if not then query price history - if($oldest > $pq['start'] + $pq['period_ms']) { + if ($oldest > $pq['start'] + $pq['period_ms']) { $pqa = $pq; $pqa['stop'] = $oldest + $pq['period_ms']; price_query($config, $pqa); @@ -385,8 +502,11 @@ function price_history($config, $pair_id = FALSE) { $history = query($query . $query_part, $config); # if there is no existing records, there is a problem - if(empty($history)) { - $config['chatText'] = 'unknown problem with price history update for pair_id ' . $pair['pair_id'] . ', unable to query data'; + if (empty($history)) { + $config['chatText'] = + 'unknown problem with price history update for pair_id ' . $pair['pair_id'] . + ', unable to query data' + ; telegram($config); echo $config['chatText'] . PHP_EOL; continue 1; @@ -397,12 +517,13 @@ function price_history($config, $pair_id = FALSE) { # update asset history summary $query_part = " - AND pair = '" . $pair['pair'] . "' - AND source = '" . $pair['source'] . "' - AND period = '" . $config['period'][$pq['period']] . "' - AND timestamp >= " . $pair['history_start'] . " - AND timestamp <= " . $pair['history_end'] . " - ORDER BY timestamp"; + AND pair = '" . $pair['pair'] . "' + AND source = '" . $pair['source'] . "' + AND period = '" . $config['period'][$pq['period']] . "' + AND timestamp >= " . $pair['history_start'] . " + AND timestamp <= " . $pair['history_end'] . " + ORDER BY timestamp + "; history_currency($config, $query . $query_part, $pq); } @@ -413,14 +534,16 @@ function price_history($config, $pair_id = FALSE) { function price_recent($config, $pair_id = FALSE) { - $query = "SELECT * FROM asset_pairs - WHERE collect - AND history_end > " . milliseconds() . " - AND currency + refresh * 60000 < " . milliseconds(); - if($pair_id) $query .= " AND pair_id = " . $pair_id; + $query = " + SELECT * FROM asset_pairs + WHERE collect + AND history_end > " . milliseconds() . " + AND currency + refresh * 60000 < " . milliseconds() + ; + if ($pair_id) $query .= " AND pair_id = " . $pair_id; $pairs = query($query, $config); - if(empty($pairs)) echo 'current'; + if (empty($pairs)) echo 'current'; else foreach ($pairs as $pair) { @@ -442,11 +565,11 @@ function price_recent($config, $pair_id = FALSE) { # define time parameters $i = floor((milliseconds() - $pq['start']) / $pq['period_ms']); - if($i > $config['obs_curr_max']) $i = $config['obs_curr_max']; + if ($i > $config['obs_curr_max']) $i = $config['obs_curr_max']; $pq['stop'] = $pq['start'] + $i * $pq['period_ms']; # exit if time period incorrect - if($pq['start'] >= $pq['stop']) continue 1; + if ($pq['start'] >= $pq['stop']) continue 1; # query price history first # if the history is complete it will not execute @@ -455,12 +578,14 @@ function price_recent($config, $pair_id = FALSE) { # ignore weekends for certain asset classes $pq['weekends'] = weekends($pair['class']); - $query = "SELECT timestamp FROM price_history - WHERE pair = '" . $pq['pair'] . "' - AND source = '" . $pq['source'] . "' - AND period = '" . $config['period'][$pq['period']] . "' - AND timestamp >= " . $pq['start'] . " - ORDER BY timestamp"; + $query = " + SELECT timestamp FROM price_history + WHERE pair = '" . $pq['pair'] . "' + AND source = '" . $pq['source'] . "' + AND period = '" . $config['period'][$pq['period']] . "' + AND timestamp >= " . $pq['start'] . " + ORDER BY timestamp + "; history_currency($config, $query, $pq); @@ -487,9 +612,9 @@ function price_missing($config, $history, $pq) { for ($i = 1; $i < $count; $i++) { # check if it indicates a broken sequence of timestamps # otherwise resume loop - if($hist[$i] - $hist[$i-1] !== $pq['period_ms']) { + if ($hist[$i] - $hist[$i - 1] !== $pq['period_ms']) { # define the first missing record in the sequence - $from = $hist[$i-1] + $pq['period_ms']; + $from = $hist[$i - 1] + $pq['period_ms']; # define the last missing record in the sequence, could be the same as the first $to = $hist[$i] - $pq['period_ms']; # query the API for the missing record(s) @@ -497,38 +622,44 @@ function price_missing($config, $history, $pq) { $pq['stop'] = $to; price_query($config, $pq); # check if missing record is returned - $query_sub = "SELECT * FROM price_history - WHERE pair = '" . $pq['pair'] . "' - AND source = '" . $pq['source'] . "' - AND period = '" . $config['period'][$pq['period']] . "' - /* query records from either side of the missing record(s) */ - AND timestamp >= " . ($from - $pq['period_ms']) . " - AND timestamp <= " . ($to + $pq['period_ms']) . - /* option to not impute values from today or yesterday */ - /* " AND timestamp < " . (milliseconds() - 1440 * 2) . */ - " ORDER BY timestamp"; + $query_sub = " + SELECT * FROM price_history + WHERE pair = '" . $pq['pair'] . "' + AND source = '" . $pq['source'] . "' + AND period = '" . $config['period'][$pq['period']] . "'" . + /* query records from either side of the missing record(s) */ + "AND timestamp >= " . ($from - $pq['period_ms']) . " + AND timestamp <= " . ($to + $pq['period_ms']) . + /* option to not impute values from today or yesterday */ + /* " AND timestamp < " . (milliseconds() - 1440 * 2) . */ + " ORDER BY timestamp + "; $sub_hist = query($query_sub, $config); # check if missing records have now been updated - if(empty($sub_hist) || count($sub_hist) < 2) break 1; + if (empty($sub_hist) || count($sub_hist) < 2) break 1; # otherwise impute missing records # create array of timestamps $timestamps = array(); - foreach($sub_hist as $sub) array_push($timestamps, $sub['timestamp']); + foreach ($sub_hist as $sub) array_push($timestamps, $sub['timestamp']); # process each timestamp for ($j = 1; $j < count($timestamps); $j++) { - $from = $timestamps[$j-1]; + $from = $timestamps[$j - 1]; # check timestamp array is valid - if(!isset($timestamps[$j])) { echo 'ERROR $j: ' . $j . PHP_EOL; var_dump($timestamps); die; } + if (!isset($timestamps[$j])) { + echo 'ERROR $j: ' . $j . PHP_EOL; + var_dump($timestamps); + die; + } $to = $timestamps[$j]; # count missing records $iter = ($to - $from) / $pq['period_ms']; # if there will be a long string of missing records, exit # accounting for weekends - if($pq['weekends']) { - if($iter > $config['obs_imp_max']) continue 1; + if ($pq['weekends']) { + if ($iter > $config['obs_imp_max']) continue 1; } else { $wmiss = count_on_weekends($from, $to, $pq['period_ms']); - if($iter - $wmiss > $config['obs_imp_max']) continue 1; + if ($iter - $wmiss > $config['obs_imp_max']) continue 1; } # iterate for each missing record for ($k = 1; $k < $iter; $k++) { @@ -537,14 +668,14 @@ function price_missing($config, $history, $pq) { $values['pair'] = $pq['pair']; $values['source'] = $pq['source']; $values['timestamp'] = $from + $k * $pq['period_ms']; - $values['period'] = $sub_hist[$j-1]['period']; - $values['open'] = $sub_hist[$j-1]['open']; - $values['close'] = $sub_hist[$j-1]['close']; - $values['high'] = $sub_hist[$j-1]['high']; - $values['low'] = $sub_hist[$j-1]['low']; - $values['volume'] = $sub_hist[$j-1]['volume']; + $values['period'] = $sub_hist[$j - 1]['period']; + $values['open'] = $sub_hist[$j - 1]['open']; + $values['close'] = $sub_hist[$j - 1]['close']; + $values['high'] = $sub_hist[$j - 1]['high']; + $values['low'] = $sub_hist[$j - 1]['low']; + $values['volume'] = $sub_hist[$j - 1]['volume']; $values['imputed'] = 1; - if($config['debug']) var_dump($values); + if ($config['debug']) var_dump($values); # update database query('update_history', $config, $values); } @@ -561,7 +692,7 @@ function price_history_imputed($config) { $query = "SELECT * FROM asset_pairs WHERE collect"; $pairs = query($query, $config); - if(!empty($pairs)) + if (!empty($pairs)) foreach ($pairs as $pair) { print_r($pair); @@ -580,45 +711,47 @@ function price_history_imputed($config) { $pq['obs_iter'] = $config['obs_iter_max']; # query imputed records - $query_sub = "SELECT * FROM price_history - WHERE pair = '" . $pq['pair'] . "' - AND source = '" . $pq['source'] . "' - AND period = '" . $config['period'][$pq['period']] . "' - AND imputed = 1 - ORDER BY timestamp"; + $query_sub = " + SELECT * FROM price_history + WHERE pair = '" . $pq['pair'] . "' + AND source = '" . $pq['source'] . "' + AND period = '" . $config['period'][$pq['period']] . "' + AND imputed = 1 + ORDER BY timestamp + "; $sub_hist = query($query_sub, $config); # check if imputed records exist - if(empty($sub_hist)) continue 1; + if (empty($sub_hist)) continue 1; # check if the asset pair is only reported on weekends /* - if(!$pq['weekends']) { + if (!$pq['weekends']) { $missing = count_on_weekends($from, $to, $period_ms); - if(!$missing) continue 1; + if (!$missing) continue 1; } */ # create array of timestamps $timestamps = array(); - foreach($sub_hist as $sub) array_push($timestamps, $sub['timestamp']); + foreach ($sub_hist as $sub) array_push($timestamps, $sub['timestamp']); $count = count($timestamps); - if($count == 1) $count = 2; + if ($count == 1) $count = 2; $pq['start'] = $timestamps[0]; for ($j = 1; $j < $count; $j++) { # check if timestamp is not a sequence with the previous one - if($timestamps[$j] - $timestamps[$j-1] !== $pq['period_ms']) { + if ($timestamps[$j] - $timestamps[$j - 1] !== $pq['period_ms']) { # if it is a new sequence then query the previous sequence - $pq['stop'] = $timestamps[$j-1]; + $pq['stop'] = $timestamps[$j - 1]; # query the API for the missing record(s) price_query($config, $pq); # define the new sequence $pq['start'] = $timestamps[$j]; } # check if the final timestamp - if($j == $count) { + if ($j == $count) { # query the final sequence $pq['stop'] = $timestamps[$j]; price_query($config, $pq); @@ -628,36 +761,37 @@ function price_history_imputed($config) { } function info_uniswap($config) { - # https://uniswap.org/docs/v2/API/queries/#pair-data - # create as array, then json_encode - $query = ' + # https://uniswap.org/docs/v2/API/queries/#pair-data + # create as array, then json_encode + /* + $query = ' { - pair(id: "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11"){ - token0 { - id - symbol - name - derivedETH - } - token1 { - id - symbol - name - derivedETH - } - reserve0 - reserve1 - reserveUSD - trackedReserveETH - token0Price - token1Price - volumeUSD - txCount +pair(id: "0xa478c2975ab1ea89e8196811f51a7b7ade33eb11"){ + token0 { + id + symbol + name + derivedETH + } + token1 { + id + symbol + name + derivedETH + } + reserve0 + reserve1 + reserveUSD + trackedReserveETH + token0Price + token1Price + volumeUSD + txCount } }'; - $config['url'] = $config['url_uniswap_graph'] . $query; - + $config['url'] = $config['url_uniswap_graph'] . $query; +*/ } diff --git a/functions.tactics.php b/functions.tactics.php index 1d62ab9..be09213 100644 --- a/functions.tactics.php +++ b/functions.tactics.php @@ -7,37 +7,37 @@ function actionable_tactics($config, $tactic_id = FALSE) { /* query actionable tactics */ $values['filterquery'] = " WHERE status = 'actionable'"; - if($tactic_id) $values['filterquery'] .= " AND tactic_id IN (" . $tactic_id . ")"; + if ($tactic_id) $values['filterquery'] .= " AND tactic_id IN (" . $tactic_id . ")"; $tactics = query('get_tactics', $config, $values); - if($config['debug']) { print_r($tactics); } + if ($config['debug']) { print_r($tactics); } - # process each action - if (!empty($tactics)) foreach ($tactics as $t) { + # process each action + if (!empty($tactics)) + foreach ($tactics as $t) { - # check if time limit for executing action has been exceeded, for instance when order attempts have failed - if($t['currency'] + $t['action_time_limit'] * 60000 < $config['timestamp']) { + # check if time limit for executing action has been exceeded, for instance when order attempts have failed + if ($t['currency'] + $t['action_time_limit'] * 60000 < $config['timestamp']) { - $query = "UPDATE tactics SET - status = 'failed', - currency = " . $config['timestamp'] . ", - WHERE tactic_id = " . $t['tactic_id'] - ; - query($query, $config); + $query = " + UPDATE tactics SET + status = 'failed', + currency = " . $config['timestamp'] . ", + WHERE tactic_id = " . $t['tactic_id'] + ; + query($query, $config); - $config['chatText'] = 'actionable tactic unable to execute for tactic_id ' . $t['tactic_id']; + $config['chatText'] = 'actionable tactic unable to execute for tactic_id ' . $t['tactic_id']; telegram($config); - continue 1; + continue 1; } $config['exchange'] = $t['exchange']; $config = config_exchange($config); - # if action is to place an order - if(in_array($t['action'], - array('limit', 'market'), - TRUE)) { + # if action is to place an order + if (in_array($t['action'], array('limit', 'market'), TRUE)) { # construct order $order_query = array( @@ -46,84 +46,87 @@ function actionable_tactics($config, $tactic_id = FALSE) { 'orderType' => $t['action'] ); - if(strpos($t['pair_asset'], $t['from_asset'] . '/') !== FALSE) { + if (strpos($t['pair_asset'], $t['from_asset'] . '/') !== FALSE) { $order_query['side'] = 'sell'; } else { $order_query['side'] = 'buy'; } - if(!empty($t['from_amount'])) { + if (!empty($t['from_amount'])) { $order_query['orderQty'] = $t['from_amount']; } elseif (!empty($t['from_percent'])) { - # to do: if percent is defined instead of amount, - # query available funds on exchange and calculate trade amount from percent + # to do: + # if percent is defined instead of amount, + # query available funds on exchange and calculate trade amount from percent } - if($order_query['orderType'] == 'limit') $order_query['orderPrice'] = $t['trade_price']; + if ($order_query['orderType'] == 'limit') $order_query['orderPrice'] = $t['trade_price']; switch($t['exchange']) { case 'bitmax': - # define response requested from exchange + # define response requested from exchange $order_query['respInst'] = 'ACCEPT'; - break; + break; case 'okex': - # 0: limit order (max price and quantity) - # 1: market order (quantity only) - # 2: fill or kill (ignore) - # 3: immediate or cancel (ignore) - if($t['action'] == 'limit') $order_query['orderTypeCode'] = 0; - if($t['action'] == 'market') $order_query['orderTypeCode'] = 1; - break; + # 0: limit order (max price and quantity) + # 1: market order (quantity only) + # 2: fill or kill (ignore) + # 3: immediate or cancel (ignore) + if ($t['action'] == 'limit') $order_query['orderTypeCode'] = 0; + if ($t['action'] == 'market') $order_query['orderTypeCode'] = 1; + break; } - # place order + # place order $result = place_order($config, $order_query, $orderId = ''); #var_dump($result); - # process response of order placed success - if($result['res']['placed']) { + # process response of order placed success + if ($result['res']['placed']) { # slight risk order is placed but response not received # could check number of open orders matches number in tactics and/or transactions - # ignore risk for now - - # record order in transactions table - $query = "INSERT INTO transactions - (exchange, exchange_transaction_id) - VALUES - ('" . $t['exchange'] . "', '" . $result['res']['exchange_transaction_id'] . "') - "; + # ignore risk for now + + # record order in transactions table + $query = " + INSERT INTO transactions + (exchange, exchange_transaction_id) + VALUES + ('" . $t['exchange'] . "', '" . $result['res']['exchange_transaction_id'] . "') + "; query($query, $config); - # record order in tactics table - $query = "SELECT transaction_id FROM transactions - WHERE exchange = '" . $t['exchange'] . "' - AND exchange_transaction_id = '" . $result['res']['exchange_transaction_id'] . "' - "; + # record order in tactics table + $query = " + SELECT transaction_id FROM transactions + WHERE exchange = '" . $t['exchange'] . "' + AND exchange_transaction_id = '" . $result['res']['exchange_transaction_id'] . "' + "; $id = query($query, $config); - $query = "UPDATE tactics SET - status = 'ordered', - currency = " . $config['timestamp'] . ", - transaction_id = " . $id[0]['transaction_id'] . " - WHERE tactic_id = " . $t['tactic_id'] - ; + $query = " + UPDATE tactics SET + status = 'ordered', + currency = " . $config['timestamp'] . ", + transaction_id = " . $id[0]['transaction_id'] . " + WHERE tactic_id = " . $t['tactic_id'] + ; query($query, $config); - # note that can leave order history to update itself + # note that we can leave order history to update itself } else { - # process response of order placed failure - # if an order fails send a message to telegram - # next time actionable_tactics function is called, bot will try to place order again + # process response of order placed failure + # if an order fails send a message to telegram + # next time actionable_tactics function is called, bot will try to place order again $config['chatText'] = 'order attempt failed for tactic_id ' . $t['tactic_id']; telegram($config); - } } @@ -132,42 +135,43 @@ function actionable_tactics($config, $tactic_id = FALSE) { /* if action is to delete order */ if ($t['action'] == 'delete') { - /* get tactic's order */ - $values['filterquery'] = " WHERE transaction_id = '" . $t['transaction_id'] . "'"; - $transaction = query('get_transactions', $config, $values); + /* get tactic's order */ + $values['filterquery'] = " WHERE transaction_id = '" . $t['transaction_id'] . "'"; + $transaction = query('get_transactions', $config, $values); - /* delete order */ - $order_query = array(); - #$order['id'] = $t['transaction_id']; # optional, for echo back - $order_query['orderId'] = $transaction[0]['exchange_transaction_id']; - $order_query['symbol'] = $transaction[0]['pair_asset']; + /* delete order */ + $order_query = array(); + #$order['id'] = $t['transaction_id']; # optional, for echo back + $order_query['orderId'] = $transaction[0]['exchange_transaction_id']; + $order_query['symbol'] = $transaction[0]['pair_asset']; - $result = cancel_order($config, $order_query); + $result = cancel_order($config, $order_query); - # process response of order deleted success - if($result['res']['placed']) { + # process response of order deleted success + if ($result['res']['placed']) { - $transaction = check_transaction($config, $t['transaction_id']); + $transaction = check_transaction($config, $t['transaction_id']); - if($transaction !== FALSE && $transaction['exchange_transaction_status'] == 'cancelled') { + if ($transaction !== FALSE && $transaction['exchange_transaction_status'] == 'cancelled') { - $query = "UPDATE tactics SET - status = 'inactive', - currency = " . $config['timestamp'] . ", - action = 'none' - WHERE tactic_id = " . $t['tactic_id'] - ; - query($query, $config); + $query = " + UPDATE tactics SET + status = 'inactive', + currency = " . $config['timestamp'] . ", + action = 'none' + WHERE tactic_id = " . $t['tactic_id'] + ; + query($query, $config); - } + } - } else { + } else { - # process response of order deleted failure - $config['chatText'] = 'delete order attempt failed for tactic_id ' . $t['tactic_id']; - telegram($config); + # process response of order deleted failure + $config['chatText'] = 'delete order attempt failed for tactic_id ' . $t['tactic_id']; + telegram($config); - } + } } @@ -180,74 +184,77 @@ function actionable_tactics($config, $tactic_id = FALSE) { function conditional_tactics($config, $tactic_id = FALSE) { $subquery = ""; - if($tactic_id) $subquery = " AND tactic_id IN (" . $tactic_id . ")"; - - /* query current tactics */ - $values['filterquery'] = " WHERE status = 'conditional' - AND currency < (" . $config['timestamp'] . " - refresh * 60000) - " . $subquery . " - ORDER BY condition_tactic DESC"; - $tactics = query('get_tactics', $config, $values); - if($config['debug']) print_r($tactics); - - # process each tactic - if (!empty($tactics)) foreach ($tactics as $t) { + if ($tactic_id) $subquery = " AND tactic_id IN (" . $tactic_id . ")"; + + /* query current tactics */ + $values['filterquery'] = " + WHERE status = 'conditional' + AND currency < (" . $config['timestamp'] . " - refresh * 60000) + " . $subquery . " + ORDER BY condition_tactic DESC + "; + $tactics = query('get_tactics', $config, $values); + if ($config['debug']) print_r($tactics); + + # process each tactic + if (!empty($tactics)) + foreach ($tactics as $t) { $update = FALSE; - /* - notes: - there are 3 possible conditions, recorded in tactics table in database: - time delay condition (condition_time) - dependent tactic condition (condition_tactic) - pair price indicator condition (condition_pair_*) - condition_time requires that a fixed amount of time has passed - condition_tactic requires that another tactic status has changed to 'executed' - condition_pair_* requires that a pair price indicator value passes a threshold value - all 3 conditions need to be met for tactic status to change from 'conditional' to 'actionable' - when a condition is met, its test variable is set to 1 - if a condition is not yet met, its test variable is set to 0 - the test variables are: - condition_time_test - condition_tactic_test - condition_pair_test - if any conditions are not used for a tactic, the test variable is set to 1 by default - */ - - # test time delay condition (condition_time), if not yet satisfied (condition_time_test=0) - if(!$t['condition_time_test']) { - if($t['condition_time'] < $config['timestamp']) { + /* + notes: + there are 3 possible conditions, recorded in tactics table in database: + time delay condition (condition_time) + dependent tactic condition (condition_tactic) + pair price indicator condition (condition_pair_*) + condition_time requires that a fixed amount of time has passed + condition_tactic requires that another tactic status has changed to 'executed' + condition_pair_* requires that a pair price indicator value passes a threshold value + all 3 conditions need to be met for tactic status to change from 'conditional' to 'actionable' + when a condition is met, its test variable is set to 1 + if a condition is not yet met, its test variable is set to 0 + the test variables are: + condition_time_test + condition_tactic_test + condition_pair_test + if any conditions are not used for a tactic, the test variable is set to 1 by default + */ + + # test time delay condition (condition_time), if not yet satisfied (condition_time_test=0) + if (!$t['condition_time_test']) { + if ($t['condition_time'] < $config['timestamp']) { $t['condition_time_test'] = 1; $update = TRUE; - if($config['debug']) echo 'condition_time_test positive' . PHP_EOL; + if ($config['debug']) echo 'condition_time_test positive' . PHP_EOL; } } - # test dependent tactic condition (condition_tactic), if not yet satisfied (condition_tactic_test=0) - # and time delay condition already satisfied - if(!$t['condition_tactic_test'] && $t['condition_time_test']) { + # test dependent tactic condition (condition_tactic), if not yet satisfied (condition_tactic_test=0) + # and time delay condition already satisfied + if (!$t['condition_tactic_test'] && $t['condition_time_test']) { $values['filterquery'] = " WHERE tactic_id = " . $t['condition_tactic']; - $res = query('get_tactics', $config, $values); - if($res[0]['status'] == 'executed') { + $res = query('get_tactics', $config, $values); + if ($res[0]['status'] == 'executed') { $t['condition_tactic_test'] = 1; $update = TRUE; - if($config['debug']) echo 'condition_tactic_test positive' . PHP_EOL; - } elseif($res[0]['status'] == 'inactive' || $res[0]['status'] == 'failed') { - # if dependent tactic is inactive or failed, change status - /* change tactic status */ - $values['tactic_id'] = $res[0]['tactic_id']; - $values['field'] = 'status'; - $values['value'] = 'inactive'; - query('update_tactic', $config, $values); - continue 1; - } + if ($config['debug']) echo 'condition_tactic_test positive' . PHP_EOL; + } elseif ($res[0]['status'] == 'inactive' || $res[0]['status'] == 'failed') { + # if dependent tactic is inactive or failed, change status + /* change tactic status */ + $values['tactic_id'] = $res[0]['tactic_id']; + $values['field'] = 'status'; + $values['value'] = 'inactive'; + query('update_tactic', $config, $values); + continue 1; + } } - # test pair price indicator condition (condition_pair_*), if not yet satisfied (condition_pair_test=0) - # and time delay and dependent tactic conditions already satisfied - if(!$t['condition_pair_test'] && $t['condition_time_test'] && $t['condition_tactic_test']) { + # test pair price indicator condition (condition_pair_*), if not yet satisfied (condition_pair_test=0) + # and time delay and dependent tactic conditions already satisfied + if (!$t['condition_pair_test'] && $t['condition_time_test'] && $t['condition_tactic_test']) { - # query the most recent price and calculate indicators first + # query the most recent price and calculate indicators first price_recent($config, $t['condition_pair_id']); technical_analysis($config, $t['condition_pair_id']); @@ -256,49 +263,61 @@ function conditional_tactics($config, $tactic_id = FALSE) { $res = query($query, $config); $a = $res[0]; $currency_min = $config['timestamp'] - $t['condition_pair_currency_min'] * 60000; - if($config['debug']) echo 'condition_pair_test if ' . $a['currency'] . ' >= ' . $currency_min . PHP_EOL; + if ($config['debug']) echo 'condition_pair_test if ' . $a['currency'] . ' >= ' . $currency_min . PHP_EOL; # check if the asset_pair is current enough, also depends on asset_pair refresh rate - if($a['currency'] >= $currency_min) { - $query = "SELECT history_id FROM price_history - WHERE pair = '" . $a['pair'] . "' - AND source = '" . $a['source'] . "' - AND period = '" . $config['period'][$a['period']] . "' - AND timestamp = " . $a['currency'] . " - AND " . $t['condition_pair_indicator'] . $t['condition_pair_value_operand'] . $t['condition_pair_value']; + if ($a['currency'] >= $currency_min) { + $query = " + SELECT history_id FROM price_history + WHERE pair = '" . $a['pair'] . "' + AND source = '" . $a['source'] . "' + AND period = '" . $config['period'][$a['period']] . "' + AND timestamp = " . $a['currency'] . " + AND " . $t['condition_pair_indicator'] . $t['condition_pair_value_operand'] . $t['condition_pair_value'] + ; $res = query($query, $config); - if($config['debug']) echo 'condition_pair_test: ' . $query . PHP_EOL; - # if any result was returned from the sql query this proves the condition has been met - if(!empty($res)) { + if ($config['debug']) echo 'condition_pair_test: ' . $query . PHP_EOL; + # if any result was returned from the sql query this proves the condition has been met + if (!empty($res)) { $t['condition_pair_test'] = 1; $update = TRUE; - if($config['debug']) echo 'condition_pair_test positive' . PHP_EOL; + if ($config['debug']) echo 'condition_pair_test positive' . PHP_EOL; } } } - # test if all 3 condition tests have been met, and if the status has changed ($update=TRUE) - if($t['condition_pair_test'] && $t['condition_time_test'] && $t['condition_tactic_test'] && $update) { - if($config['debug']) echo 'status change' . PHP_EOL; - if($t['action'] == 'none') { + # test if all 3 condition tests have been met, and if the status has changed ($update=TRUE) + if ( + $t['condition_pair_test'] && + $t['condition_time_test'] && + $t['condition_tactic_test'] && + $update + ) { + if ($config['debug']) echo 'status change' . PHP_EOL; + if ($t['action'] == 'none') { $t['status'] = 'executed'; } else { $t['status'] = 'actionable'; - $config['chatText'] = 'trade ready, attempting to ' . $t['action'] . ' order for ' . $t['from_asset'] . ' ' . $t['to_asset'] . ' on ' . $t['exchange']; + $config['chatText'] = + 'trade ready, attempting to ' . $t['action'] . + ' order for ' . $t['from_asset'] . ' ' . $t['to_asset'] . + ' on ' . $t['exchange']; telegram($config); } } - # update the tactics status if necessary - if($update) { - $query = "UPDATE tactics SET - status = '" . $t['status'] . "' - ,condition_tactic_test = " . $t['condition_tactic_test'] . " - ,condition_time_test = " . $t['condition_time_test'] . " - ,condition_pair_test = " . $t['condition_pair_test'] . " - ,currency = " . $config['timestamp'] . " - WHERE tactic_id = " . $t['tactic_id']; - query($query, $config); - if($config['debug']) echo 'update record' . PHP_EOL; + # update the tactics status if necessary + if ($update) { + $query = " + UPDATE tactics SET + status = '" . $t['status'] . "' + ,condition_tactic_test = " . $t['condition_tactic_test'] . " + ,condition_time_test = " . $t['condition_time_test'] . " + ,condition_pair_test = " . $t['condition_pair_test'] . " + ,currency = " . $config['timestamp'] . " + WHERE tactic_id = " . $t['tactic_id'] + ; + query($query, $config); + if ($config['debug']) echo 'update record' . PHP_EOL; } } } @@ -308,70 +327,76 @@ function conditional_tactics($config, $tactic_id = FALSE) { function ordered_tactics($config, $tactic_id = FALSE) { /* query tactics */ - $subquery = ""; - if($tactic_id) $subquery = " AND tactic_id IN (" . $_GET['tactic_id'] . ")"; - - $values['filterquery'] = " WHERE status = 'ordered' - AND currency < (" . $config['timestamp'] . " - refresh * 60000)" - . $subquery; - if($tactic_id) $values['filterquery'] .= " AND tactic_id IN (" . $tactic_id . ")"; + $subquery = ""; + if ($tactic_id) $subquery = " AND tactic_id IN (" . $_GET['tactic_id'] . ")"; + + $values['filterquery'] = " + WHERE status = 'ordered' + AND currency < (" . $config['timestamp'] . " - refresh * 60000)" . + $subquery + ; + if ($tactic_id) $values['filterquery'] .= " AND tactic_id IN (" . $tactic_id . ")"; $tactics = query('get_tactics', $config, $values); - if($config['debug']) { print_r($tactics); } + if ($config['debug']) { print_r($tactics); } - if (!empty($tactics)) foreach ($tactics as $t) { + if (!empty($tactics)) + foreach ($tactics as $t) { /* get tactic's order */ - if(!empty($t['transaction_id'])) { - - $order = check_transaction($config, $t['transaction_id']); + if (!empty($t['transaction_id'])) { + + $order = check_transaction($config, $t['transaction_id']); } else { - # process response of transaction_id not recorded - $config['chatText'] = 'query tactic transaction_id attempt failed for tactic_id ' . $t['tactic_id']; - telegram($config); + # process response of transaction_id not recorded + $config['chatText'] = 'query tactic transaction_id attempt failed for tactic_id ' . $t['tactic_id']; + telegram($config); - continue 1; + continue 1; - } + } - if($config['debug']) { echo $config['url'] . PHP_EOL; print_r($order); } + if ($config['debug']) { echo $config['url'] . PHP_EOL; print_r($order); } - $update = FALSE; + $update = FALSE; /* check if order completed */ if ($order['exchange_transaction_status'] == 'complete') { - $values['value'] = 'executed'; - $update = TRUE; + $values['value'] = 'executed'; + $update = TRUE; } /* check if order cancelled */ - if ($order['exchange_transaction_status'] == 'cancelled') { + if ($order['exchange_transaction_status'] == 'cancelled') { - $values['value'] = 'inactive'; - $update = TRUE; + $values['value'] = 'inactive'; + $update = TRUE; } - /* process update */ - if($update) { - - /* change tactic status */ - $values['tactic_id'] = $t['tactic_id']; - $values['field'] = 'status'; - query('update_tactic', $config, $values); + /* process update */ + if ($update) { + + /* change tactic status */ + $values['tactic_id'] = $t['tactic_id']; + $values['field'] = 'status'; + query('update_tactic', $config, $values); + + /* query any conditional tactics */ + $values['filterquery'] = " + WHERE status = 'conditional' + AND condition_tactic = '" . $t['tactic_id'] . "'" + ; + $triggers = query('get_tactics', $config, $values); + if ($config['debug']) print_r($triggers); + if (!empty($triggers)) + foreach ($triggers as $trigger) + conditional_tactics($config, $trigger['tactic_id']); - /* query any conditional tactics */ - $values['filterquery'] = " WHERE status = 'conditional' - AND condition_tactic = '" . $t['tactic_id'] . "'"; - $triggers = query('get_tactics', $config, $values); - if($config['debug']) { print_r($triggers); } - if (!empty($triggers)) foreach ($triggers as $trigger) - conditional_tactics($config, $trigger['tactic_id']); - - } + } } diff --git a/functions.util.php b/functions.util.php index 9c5dd91..a84fc02 100644 --- a/functions.util.php +++ b/functions.util.php @@ -1,107 +1,115 @@ url = $url; - } - - /** - * @param $httpheader array of headers - * @return response - */ - public function call($httpheader, $method, $query = NULL) - { - try - { - $curl = curl_init(); - if (FALSE === $curl) - throw new Exception('Failed to initialize'); - - $curl_opt = array( - CURLOPT_URL => $this->url, - CURLOPT_RETURNTRANSFER => true, - CURLOPT_ENCODING => "", - CURLOPT_MAXREDIRS => 10, - CURLOPT_TIMEOUT => 60, /* number of seconds to wait for response */ - CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, - CURLOPT_CUSTOMREQUEST => $method, - CURLOPT_POSTFIELDS => $query, - CURLOPT_HTTPHEADER => $httpheader - ); - curl_setopt_array($curl, $curl_opt); - - $response = curl_exec($curl); - if (FALSE === $response) - throw new Exception(curl_error($curl), curl_errno($curl)); - - $http_status = curl_getinfo($curl, CURLINFO_HTTP_CODE); - - if (200 != $http_status) - throw new Exception($response, $http_status); - curl_close($curl); - } - catch(Exception $e) - { - $response= $e->getCode() . $e->getMessage(); - - echo $response; - } - return $response; - } +class APIREST { + + private $url; + + public function __construct($url) { + $this->url = $url; + } + + /** + * @param $httpheader array of headers + * @return response + */ + public function call($httpheader, $method, $query = NULL) { + + try { + + $curl = curl_init(); + if (FALSE === $curl) + throw new Exception('Failed to initialize'); + + $curl_opt = array( + CURLOPT_URL => $this->url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_ENCODING => "", + CURLOPT_MAXREDIRS => 10, + CURLOPT_TIMEOUT => 60, /* number of seconds to wait for response */ + CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, + CURLOPT_CUSTOMREQUEST => $method, + CURLOPT_POSTFIELDS => $query, + CURLOPT_HTTPHEADER => $httpheader + ); + curl_setopt_array($curl, $curl_opt); + + $response = curl_exec($curl); + if (FALSE === $response) + throw new Exception(curl_error($curl), curl_errno($curl)); + + $http_status = curl_getinfo($curl, CURLINFO_HTTP_CODE); + + if (200 != $http_status) + throw new Exception($response, $http_status); + curl_close($curl); + + } catch(Exception $e) { + $response= $e->getCode() . $e->getMessage(); + echo $response; + } + + return $response; + } } /* get timestamp */ function milliseconds() { - list($msec, $sec) = explode(' ', microtime()); - return (int) ($sec . substr($msec, 2, 3)); + + list($msec, $sec) = explode(' ', microtime()); + return (int) ($sec . substr($msec, 2, 3)); + } /* encrypt key */ function hmac($msg, $secret) { - $hmac = hash_hmac('sha256', $msg, $secret, true); - $hmac = base64_encode($hmac); - return $hmac; + + $hmac = hash_hmac('sha256', $msg, $secret, true); + $hmac = base64_encode($hmac); + return $hmac; + } /* array depth */ function countdim($array) { - if (is_array(reset($array))) { - $return = countdim(reset($array)) + 1; - } else { - $return = 1; - } - return $return; + + if (is_array(reset($array))) { + $return = countdim(reset($array)) + 1; + } else { + $return = 1; + } + return $return; + } -/* asset pair only reported on weekdays - expect some asset pairs are not recorded on weekends, for instance fiat currencies like $AUD to $USD +/* +asset pair only reported on weekdays +expect some asset pairs are not recorded on weekends, for instance fiat currencies like $AUD to $USD */ function weekends($class) { - if($class == 'fiat' || $class == 'stock') { - $weekend = FALSE; - } else { - $weekend = TRUE; - } - return $weekend; + + if ($class == 'fiat' || $class == 'stock') { + $weekend = FALSE; + } else { + $weekend = TRUE; + } + return $weekend; + } /* count number of observations falling on weekends */ function count_on_weekends($from, $to, $period_ms) { - $wmiss = 0; - for ($j = $from; $j <= $to; $j += $period_ms) { - $day = date('l', $j / 1000); - if(!($day == 'Sunday' || $day == 'Monday')) $wmiss++; - #echo 'check UTC ' . date('Y-m-d H:i:s', $j / 1000) . ' ' . $day . PHP_EOL; - } - return $wmiss; + + $wmiss = 0; + for ($j = $from; $j <= $to; $j += $period_ms) { + $day = date('l', $j / 1000); + if (!($day == 'Sunday' || $day == 'Monday')) $wmiss++; + } + return $wmiss; + } diff --git a/index.php b/index.php index 3957520..922668f 100644 --- a/index.php +++ b/index.php @@ -2,45 +2,45 @@ include('includes.php'); -if(isset($_GET['exchange'])) { $config['exchange'] = $_GET['exchange']; } else { $config['exchange'] = ''; } -if(isset($_GET['query'])) { $query = $_GET['query']; } else { $query = ''; } -if(isset($_GET['action'])) { $action = $_GET['action']; } else { $action = ''; } -if(isset($_GET['id'])) { $id = $_GET['id']; } else { $id = ''; } -if(isset($_GET['var1'])) { $var1 = $_GET['var1']; } else { $var1 = ''; } -if(isset($_GET['var2'])) { $var2 = $_GET['var2']; } else { $var2 = ''; } -if(isset($_GET['var3'])) { $var3 = $_GET['var3']; } else { $var3 = ''; } -if(isset($_GET['var4'])) { $var4 = $_GET['var4']; } else { $var4 = ''; } -if(isset($_GET['var5'])) { $var5 = $_GET['var5']; } else { $var5 = ''; } -if(isset($_GET['var6'])) { $var6 = $_GET['var6']; } else { $var6 = ''; } -if(isset($_GET['var7'])) { $var7 = $_GET['var7']; } else { $var7 = ''; } +if (isset($_GET['exchange'])) { $config['exchange'] = $_GET['exchange']; } else { $config['exchange'] = ''; } +if (isset($_GET['query'])) { $query = $_GET['query']; } else { $query = ''; } +if (isset($_GET['action'])) { $action = $_GET['action']; } else { $action = ''; } +if (isset($_GET['id'])) { $id = $_GET['id']; } else { $id = ''; } +if (isset($_GET['var1'])) { $var1 = $_GET['var1']; } else { $var1 = ''; } +if (isset($_GET['var2'])) { $var2 = $_GET['var2']; } else { $var2 = ''; } +if (isset($_GET['var3'])) { $var3 = $_GET['var3']; } else { $var3 = ''; } +if (isset($_GET['var4'])) { $var4 = $_GET['var4']; } else { $var4 = ''; } +if (isset($_GET['var5'])) { $var5 = $_GET['var5']; } else { $var5 = ''; } +if (isset($_GET['var6'])) { $var6 = $_GET['var6']; } else { $var6 = ''; } +if (isset($_GET['var7'])) { $var7 = $_GET['var7']; } else { $var7 = ''; } $config = config_exchange($config); echo '
';
 
 # test uniswap
-# y.jules.net.au/index.php?action=action_tactics&id=1
-if($action == 'uniswap') {
+# index.php?action=uniswap&id=1
+if ($action == 'uniswap') {
 
-    $result = info_uniswap($config);
-    var_dump($result);
+	$result = info_uniswap($config);
+	var_dump($result);
 
 }
 
 # process actionable tactics
-# y.jules.net.au/index.php?action=check_transaction&transaction_id=171
-if($action == 'check_transaction') {
+# index.php?action=check_transaction&transaction_id=171
+if ($action == 'check_transaction') {
 
 	check_transaction($config, $_GET['transaction_id']);
 
 }
 
 # process actionable tactics
-# y.jules.net.au/index.php?action=actionable_tactics&tactic_id=108,107
-if($action == 'actionable_tactics') {
+# index.php?action=actionable_tactics&tactic_id=108,107
+if ($action == 'actionable_tactics') {
 
 	$tactic_id = FALSE;
-	if(isset($_GET['tactic_id'])) $tactic_id = $_GET['tactic_id'];
+	if (isset($_GET['tactic_id'])) $tactic_id = $_GET['tactic_id'];
 
 	actionable_tactics($config, $tactic_id);
 
@@ -48,63 +48,61 @@
 
 
 # refresh tactic
-# y.jules.net.au/index.php?action=conditional_tactics&tactic_id=108,107
-if($action == 'conditional_tactics') {
+# index.php?action=conditional_tactics&tactic_id=108,107
+if ($action == 'conditional_tactics') {
 
-    $tactic_id = FALSE;
-	if(isset($_GET['tactic_id'])) $tactic_id = $_GET['tactic_id'];
+	$tactic_id = FALSE;
+	if (isset($_GET['tactic_id'])) $tactic_id = $_GET['tactic_id'];
 
 	conditional_tactics($config, $tactic_id);
 
 }
 
 # refresh tactic
-# y.jules.net.au/index.php?action=ordered_tactics&tactic_id=108,107
-if($action == 'ordered_tactics') {
+# index.php?action=ordered_tactics&tactic_id=108,107
+if ($action == 'ordered_tactics') {
 
-    $tactic_id = FALSE;
-	if(isset($_GET['tactic_id'])) $tactic_id = $_GET['tactic_id'];
+	$tactic_id = FALSE;
+	if (isset($_GET['tactic_id'])) $tactic_id = $_GET['tactic_id'];
 
 	ordered_tactics($config, $tactic_id);
 
 }
 
 # current price
-# y.jules.net.au/index.php?exchange=bitmax&query=price_current&var1=STAKE/USDT
-if($query == 'price_current') {
-    $config['api_request'] = 'balance';
-    $coins = '?symbol=' . $var1;
-    $config['url'] .= $config['price'] . $coins;
-    $result = info($config);
-    if($config['debug']) { echo $config['url'] . PHP_EOL; print_r($result); }
+# index.php?exchange=bitmax&query=price_current&var1=STAKE/USDT
+if ($query == 'price_current') {
+
+	$config['api_request'] = 'balance';
+	$coins = '?symbol=' . $var1;
+	$config['url'] .= $config['price'] . $coins;
+	$result = info($config);
+	if ($config['debug']) { echo $config['url'] . PHP_EOL; print_r($result); }
+
 }
 
 # historical price
-# y.jules.net.au/index.php?exchange=bitmax&query=price_history&var1=STAKE/USDT&var2=10080&var3=5&var4=1600473700000&var5=1605677000000
-# y.jules.net.au/index.php?exchange=okex&query=price_history&archive=TRUE&var1=BTC-USDT&var2=1440&var3=200&var4=1592573700000&var5=1593677000000
-# y.jules.net.au/index.php?exchange=twelve&query=price_history&var1=ETH/BTC&var2=1440&var3=5000&var4=1592573700000&var5=1593677000000
-
-# y.jules.net.au/index.php?exchange=okex&query=price_history&archive=TRUE&pair=BTC-USDT&period=1440&obs_iter=200&start=1592573700000&stop=1593677000000
-if($query == 'price_history') {
-
-	if(isset($_GET['pair'])) { $pair = $_GET['pair']; } else { $pair = ''; }
-	if(isset($_GET['period'])) { $period = $_GET['period']; } else { $period = ''; }
-	if(isset($_GET['archive'])) { $archive = $_GET['archive']; } else { $archive = FALSE; }
-	if(isset($_GET['obs_iter'])) { $obs_iter = $_GET['obs_iter']; } else {
-		if($archive) {
-				$obs_iter = $config['obs_iter_hist'];
+# index.php?exchange=okex&query=price_history&archive=TRUE&pair=BTC-USDT&period=1440&obs_iter=200&start=1592573700000&stop=1593677000000
+if ($query == 'price_history') {
+
+	if (isset($_GET['pair'])) { $pair = $_GET['pair']; } else { $pair = ''; }
+	if (isset($_GET['period'])) { $period = $_GET['period']; } else { $period = ''; }
+	if (isset($_GET['archive'])) { $archive = $_GET['archive']; } else { $archive = FALSE; }
+	if (isset($_GET['obs_iter'])) { $obs_iter = $_GET['obs_iter']; } else {
+		if ($archive) {
+			$obs_iter = $config['obs_iter_hist'];
 		} else $obs_iter = $config['obs_iter_curr'];
 	}
 
 	# calculate time periods
 	$period_ms = $period * 60000;
 	$current_period = floor(milliseconds()/$period_ms) * $period_ms;
-	if(isset($_GET['start'])) { $start = $_GET['start']; } else { $start = $current_period - $period_ms * $obs_iter; }
-	if(isset($_GET['stop'])) { $stop = $_GET['stop']; } else { $stop = $current_period; }
+	if (isset($_GET['start'])) { $start = $_GET['start']; } else { $start = $current_period - $period_ms * $obs_iter; }
+	if (isset($_GET['stop'])) { $stop = $_GET['stop']; } else { $stop = $current_period; }
 	echo '$start: ' . $start . ' $stop: ' . $stop . '
'; echo '$start: ' . date('Y-m-d H:i:s', $start / 1000) . ' $stop: ' . date('Y-m-d H:i:s', $stop / 1000) . '
'; - # array format defined in config.php + # array format defined in config.php $ph = $config['price_query']; $ph['pair'] = $pair; $ph['period'] = $period; @@ -119,104 +117,121 @@ } # deduplicate history -# y.jules.net.au/index.php?query=price_history_dedupe -if($query == 'price_history_dedupe') { +# index.php?query=price_history_dedupe +if ($query == 'price_history_dedupe') { + + echo '
';
+	price_history_dedupe();
 
-		echo '
';
-		price_history_dedupe();
 }
 
 # order book
-if($query == 'order_book') {
-    $config['api_request'] = 'depth';
-    $coins = '?symbol=' . $var1;
-    $config['url'] .= $config['order_book'] . $coins;
-    $result = info($config);
-    if($config['debug']) { echo $config['url'] . PHP_EOL; print_r($result); }
+if ($query == 'order_book') {
+
+	$config['api_request'] = 'depth';
+	$coins = '?symbol=' . $var1;
+	$config['url'] .= $config['order_book'] . $coins;
+	$result = info($config);
+	if ($config['debug']) { echo $config['url'] . PHP_EOL; print_r($result); }
+
 }
 
 # recent trades
-if($query == 'recent_trades') {
-    $config['api_request'] = 'trades';
-    $coins = '?symbol=' . $var1;
-    $number = '&n=100';
-    $config['url'] .= $config['recent_trades'] . $coins . $number;
-    $result = info($config);
-    if($config['debug']) { echo $config['url'] . PHP_EOL; print_r($result); }
+if ($query == 'recent_trades') {
+
+	$config['api_request'] = 'trades';
+	$coins = '?symbol=' . $var1;
+	$number = '&n=100';
+	$config['url'] .= $config['recent_trades'] . $coins . $number;
+	$result = info($config);
+	if ($config['debug']) { echo $config['url'] . PHP_EOL; print_r($result); }
+
 }
 
 # account balance
-if($query == 'balance') {
-    $config['api_request'] = 'balance';
-    $config['url'] .= $config['group'] . $config['balance'];
-    $result = info($config);
-    if($config['debug']) { echo $config['url'] . PHP_EOL; print_r($result); }
+if ($query == 'balance') {
+
+	$config['api_request'] = 'balance';
+	$config['url'] .= $config['group'] . $config['balance'];
+	$result = info($config);
+	if ($config['debug']) { echo $config['url'] . PHP_EOL; print_r($result); }
+
 }
 
 # account info
-if($query == 'account_info') {
+if ($query == 'account_info') {
 
-		switch ($config['exchange']) {
+	switch ($config['exchange']) {
 
-			case 'bitmax': $config['api_request'] = 'user/info';
-				break;
+		case 'bitmax':
+			$config['api_request'] = 'user/info';
+		break;
 
-			case 'okex': $config['api_request'] = $config['account_info'];
-				break;
+		case 'okex':
+			$config['api_request'] = $config['account_info'];
+		break;
 
-		}
+	}
+
+	$config['url'] .= $config['account_info'];
+	$result = info($config);
+	if ($config['debug']) { echo 'url: ' . $config['url'] . PHP_EOL . 'result: '; print_r($result); }
 
-		$config['url'] .= $config['account_info'];
-    $result = info($config);
-    if($config['debug']) { echo 'url: ' . $config['url'] . PHP_EOL . 'result: '; print_r($result); }
 }
 
 # update open orders
-if($query == 'open_orders') {
-    # http://y.jules.net.au/index.php?exchange=bitmax&query=open_orders
-    $config['api_request'] = 'order/open';
-    $config['url'] .= $config['group'] . $config['open_orders'];
-    $result = info($config);
+if ($query == 'open_orders') {
+
+	# index.php?exchange=bitmax&query=open_orders
+	$config['api_request'] = 'order/open';
+	$config['url'] .= $config['group'] . $config['open_orders'];
+	$result = info($config);
 
-    if($config['debug']) { echo $config['url'] . PHP_EOL; print_r($result); }
+	if ($config['debug']) { echo $config['url'] . PHP_EOL; print_r($result); }
+
+	update_transactions($config, $result);
 
-    update_transactions($config, $result);
 }
 
 # update history orders
-if($query == 'history_orders' && $action == 'save') {
-    # http://y.jules.net.au/index.php?exchange=bitmax&query=history_orders&action=save
-	# http://y.jules.net.au/index.php?exchange=okex&query=history_orders&action=save&pair=CVP/USDT
+if ($query == 'history_orders' && $action == 'save') {
+
+	# index.php?exchange=bitmax&query=history_orders&action=save
+	# index.php?exchange=okex&query=history_orders&action=save&pair=CVP/USDT
 
-	if(isset($_GET['pair'])) $config['pair'] = $_GET['pair'];
-	if(isset($_GET['exchange'])) $config['exchange'] = $_GET['exchange'];
-    update_transactions($config);
+	if (isset($_GET['pair'])) $config['pair'] = $_GET['pair'];
+	if (isset($_GET['exchange'])) $config['exchange'] = $_GET['exchange'];
+	update_transactions($config);
 
 }
 
 # calculate orders
-if($query == 'calculate_orders') {
-	# http://y.jules.net.au/index.php?query=calculate_orders
+if ($query == 'calculate_orders') {
+
+	# index.php?query=calculate_orders
 
 	calculate_orders($config);
 
 }
 
 # list history orders
-if($query == 'history_orders' && $action == 'print') {
-    # http://y.jules.net.au/index.php?exchange=bitmax&query=history_orders&action=print
-    $config['api_request'] = 'order/hist/current';
-    $config['url'] .= $config['group'] . $config['order_history'];
-    $config['url'] .= '?executedOnly=1&n=1000';
-    $result = info($config);
-    if($config['debug']) { echo $config['url'] . PHP_EOL; print_r($result); }
+if ($query == 'history_orders' && $action == 'print') {
+
+	# index.php?exchange=bitmax&query=history_orders&action=print
+	$config['api_request'] = 'order/hist/current';
+	$config['url'] .= $config['group'] . $config['order_history'];
+	$config['url'] .= '?executedOnly=1&n=1000';
+	$result = info($config);
+	if ($config['debug']) { echo $config['url'] . PHP_EOL; print_r($result); }
+
 }
 
 # place order
-if($query == 'place_order') {
+if ($query == 'place_order') {
+
 	/*
-	y.jules.net.au/index.php?exchange=bitmax&query=place_order&symbol=STAKE/USDT&orderPrice=40.00&orderQty=1&orderType=limit&side=sell&respInst=ACCEPT
-	y.jules.net.au/index.php?
+	index.php?exchange=bitmax&query=place_order&symbol=STAKE/USDT&orderPrice=40.00&orderQty=1&orderType=limit&side=sell&respInst=ACCEPT
+	index.php?
 	exchange=bitmax
 	&query=place_order
 	&orderId=12345678Z
@@ -227,8 +242,8 @@
 	&side=sell
 	&respInst=ACCEPT
 
-	y.jules.net.au/index.php?exchange=okex&query=place_order&symbol=ETH/USDT&orderPrice=40.00&orderQty=1&orderType=limit&orderTypeCode=0&side=sell
-	y.jules.net.au/index.php?
+	index.php?exchange=okex&query=place_order&symbol=ETH/USDT&orderPrice=40.00&orderQty=1&orderType=limit&orderTypeCode=0&side=sell
+	index.php?
 	exchange=bitmax
 	&query=place_order
 	&orderId=12345678Z
@@ -247,36 +262,39 @@
 }
 
 # cancel order
-if($query == 'cancel_order') {
-    # y.jules.net.au/index.php?exchange=bitmax&query=cancel_order&var1=12345678Z&var2=12345678Z&var3=STAKE/USDT
+if ($query == 'cancel_order') {
+
+	# index.php?exchange=bitmax&query=cancel_order&var1=12345678Z&var2=12345678Z&var3=STAKE/USDT
 
-    $order = array();
-    $order['id'] = $var1;  # optional, for echo back
-    $order['orderId'] = $var2;
-    $order['symbol'] = $var3;
-    $order['time'] = (int)$config['timestamp'];
+	$order = array();
+	$order['id'] = $var1;  # optional, for echo back
+	$order['orderId'] = $var2;
+	$order['symbol'] = $var3;
+	$order['time'] = (int)$config['timestamp'];
 
-    $result = cancel_order($config, $order);
+	$result = cancel_order($config, $order);
 
 }
 
 # delete all orders (by symbol)
-if($query == 'delete_all_order') {
-    # y.jules.net.au/index.php?exchange=bitmax&query=delete_all_order&var1=ETH/USDT
-    $config['api_request'] = 'order/all';
-    $config['url'] .= $config['group'] . $config['delete_all'];
-    $config['method'] = 'DELETE';
-
-    $order = array();
-    $order['symbol'] = $var1; # optional limit to coin pair
-
-    $result = order($config, $order);
-
-    if($config['debug']) {
-        echo $config['url'] . PHP_EOL;
-        print_r($order) . PHP_EOL;
-        print_r($result) . PHP_EOL;
-    }
+if ($query == 'delete_all_order') {
+
+	# index.php?exchange=bitmax&query=delete_all_order&var1=ETH/USDT
+	$config['api_request'] = 'order/all';
+	$config['url'] .= $config['group'] . $config['delete_all'];
+	$config['method'] = 'DELETE';
+
+	$order = array();
+	$order['symbol'] = $var1; # optional limit to coin pair
+
+	$result = order($config, $order);
+
+	if ($config['debug']) {
+		echo $config['url'] . PHP_EOL;
+		print_r($order) . PHP_EOL;
+		print_r($result) . PHP_EOL;
+	}
+
 }
 
 include('system_metrics.php');
diff --git a/mysql.db.php b/mysql.db.php
index ded01c3..490e55a 100644
--- a/mysql.db.php
+++ b/mysql.db.php
@@ -4,66 +4,57 @@
 
 function query($querylabel, $config, $values=NULL) {
 
-    # grab correct query string from query library array
-    # values automatically inserted into array
-    $query = getsql($config, $values, $querylabel);
-
-    # perform query
-    $result=doQuery($query, $config);
-
-    # for testing only: display query
-    if ($config['debug_sql']) {
-        echo "Query: ". $querylabel . PHP_EOL;
-        echo "Values: ";
-        print_r($values) . PHP_EOL;
-        echo "Result: ";
-        print_r($result) . PHP_EOL;
-        echo "Config: ";
-        var_dump($config) . PHP_EOL;
-    }
-
-    return $result;
+	# grab correct query string from query library array
+	# values automatically inserted into array
+	$query = getsql($config, $values, $querylabel);
+
+	# perform query
+	$result=doQuery($query, $config);
+
+	# for testing only: display query
+	if ($config['debug_sql']) {
+		echo "Query: ". $querylabel . PHP_EOL;
+		echo "Values: ";
+		print_r($values) . PHP_EOL;
+		echo "Result: ";
+		print_r($result) . PHP_EOL;
+		echo "Config: ";
+		var_dump($config) . PHP_EOL;
+	}
+
+	return $result;
 
 }
 
 function doQuery($query, $config) {
 
-    $reply = mysqli_query($config['sql_link'], $query);
-
-    # failed query - return FALSE
-    if ($reply === FALSE) {
-
-        $result = FALSE;
-
-    # return number of rows changed
-    } elseif ($reply === TRUE) {
-
-        $result = mysqli_affected_rows($config['sql_link']);
-
-    # check if select returns zero
-    } else if (mysqli_num_rows($reply) === 0) {
-
-        $result = 0;
-
-    # successful select - return array of results
-    } else {
-
-        # note that very large result (> 100000) can exceed memory limit
-
-        $result = array();
-        while ($mysql_result = mysqli_fetch_assoc($reply))
-            $result[] = $mysql_result;
-
-    }
+	$reply = mysqli_query($config['sql_link'], $query);
+
+	# failed query - return FALSE
+	if ($reply === FALSE) {
+		$result = FALSE;
+	# return number of rows changed
+	} elseif ($reply === TRUE) {
+		$result = mysqli_affected_rows($config['sql_link']);
+	# check if select returns zero
+	} else if (mysqli_num_rows($reply) === 0) {
+		$result = 0;
+	# successful select - return array of results
+	} else {
+		# note that very large result (> 100000) can exceed memory limit
+		$result = array();
+		while ($mysql_result = mysqli_fetch_assoc($reply))
+			$result[] = $mysql_result;
+	}
 
-    # get last autoincrement insert id
-    # $GLOBALS['lastinsertid'] = mysqli_insert_id($config['sql_link']);
+	# get last autoincrement insert id
+	# $GLOBALS['lastinsertid'] = mysqli_insert_id($config['sql_link']);
 
-    $error = mysqli_errno($config['sql_link']);
-    if ($error) $_SESSION['message'][]=
-                "Error $error in query: '" . mysqli_error($config['sql_link']) . "'";
+	$error = mysqli_errno($config['sql_link']);
+	if ($error) $_SESSION['message'][] =
+		"Error $error in query: '" . mysqli_error($config['sql_link']) . "'";
 
-    return $result;
+	return $result;
 
 }
 
@@ -78,18 +69,15 @@ function safeIntoDB(&$value, $key, $config) {
 	} else {
 
 		# don't clean filters - we've cleaned those separately in the sqlparts function
-		if (strpos($key,'filterquery') === FALSE
-			&& !preg_match("/^'\d\d\d\d-\d\d-\d\d'$/",$value) ) { // and don't clean dates
-
+		if (
+			strpos($key,'filterquery') === FALSE
+			&& !preg_match("/^'\d\d\d\d-\d\d-\d\d'$/",$value)
+		) { // and don't clean dates
 			if (ini_get('magic_quotes_gpc') && !empty($value) && is_string($value))
 				$value = stripslashes($value);
-
 			$value = mysqli_real_escape_string($config['sql_link'], $value);
-
 		} else {
-
-		    return $value;
-
+			return $value;
 		}
 
 		return $value;
diff --git a/mysql.inc.php b/mysql.inc.php
index 062cfee..ac9b04c 100644
--- a/mysql.inc.php
+++ b/mysql.inc.php
@@ -2,211 +2,223 @@
 
 function getsql($config, $values, $querylabel) {
 
-    if (is_array($values))
-        foreach ($values as $key => $value)
-            $values[$key] = safeIntoDB($value, $key, $config);
+	if (is_array($values))
+		foreach ($values as $key => $value)
+			$values[$key] = safeIntoDB($value, $key, $config);
 
 	switch ($querylabel) {
 
-        case 'select_indicators':
-            $sql = "SELECT
-                    `function`,
-                    `description`,
-                    `indication`,
-                    `class`
-                    FROM `indicators` {$values['filterquery']}
-            ";
-            break;
-
-        case 'select_history':
-            $sql = "SELECT
-                    `history_id`,
-                    `timestamp`,
-                    `open`,
-                    `close`,
-                    `high`,
-                    `low`,
-                    `volume`
-                    FROM `price_history` {$values['filterquery']}
-            ";
-            break;
-
-        case 'update_history':
-            $sql = "INSERT INTO `price_history`
-                    (
-                    `pair`,
-                    `source`,
-                    `timestamp`,
-                    `period`,
-                    `open`,
-                    `close`,
-                    `high`,
-                    `low`,
-                    `volume`,
-                    `imputed`
-                    )
-                    VALUES
-                    (
-                    '{$values['pair']}',
-                    '{$values['source']}',
-                    '{$values['timestamp']}',
-                    '{$values['period']}',
-                    '{$values['open']}',
-                    '{$values['close']}',
-                    '{$values['high']}',
-                    '{$values['low']}',
-                    '{$values['volume']}',
-                    '{$values['imputed']}'
-                    )
-            ";
-            break;
-
-				# keep the most recent record
-				case 'deduplicate_history':
-
-						# warning this is inefficient with a large db, better to iterate with $values filter to small number of records
-						$sql = "
-                DELETE a FROM `price_history` a
-                INNER JOIN `price_history` b
-								ON a.pair = b.pair
-                AND a.timestamp = b.timestamp
-                AND a.period = b.period
-                AND a.source = b.source
-                WHERE
-                    a.history_id < b.history_id
-                    {$values['filterquery']}
-										;
-            		";
-
-            break;
-
-        case 'update_content':
-            $sql = "REPLACE INTO `web_content`
-                    (
-                    `content_id`,
-                    `content`,
-                    `timestamp`,
-                    `notified`
-                    )
-                    VALUES
-                    (
-                    '{$values['content_id']}',
-                    '{$values['content']}',
-                    '{$values['timestamp']}',
-                    '{$values['notified']}'
-                    )
-            ";
-            break;
-
-        case 'get_content':
-            $sql = "SELECT * FROM `web_content` {$values['filterquery']}";
-            break;
-
-        case 'get_tactics':
-            $sql = "SELECT * FROM `tactics` {$values['filterquery']}";
-            break;
-
-        case 'update_tactic':
-            $sql = "UPDATE `tactics` SET `{$values['field']}` = '{$values['value']}' WHERE `tactic_id` = '{$values['tactic_id']}'";
-            break;
-
-        case 'get_transactions':
-            $sql = "SELECT * FROM `transactions` {$values['filterquery']}";
-            break;
+		case 'select_indicators':
+			$sql = "
+				SELECT
+				`function`,
+				`description`,
+				`indication`,
+				`class`
+				FROM `indicators` {$values['filterquery']}
+			";
+		break;
+
+		case 'select_history':
+			$sql = "SELECT
+				`history_id`,
+				`timestamp`,
+				`open`,
+				`close`,
+				`high`,
+				`low`,
+				`volume`
+				FROM `price_history` {$values['filterquery']}
+			";
+		break;
+
+		case 'update_history':
+			$sql = "
+				INSERT INTO `price_history`
+				(
+				`pair`,
+				`source`,
+				`timestamp`,
+				`period`,
+				`open`,
+				`close`,
+				`high`,
+				`low`,
+				`volume`,
+				`imputed`
+				)
+				VALUES
+				(
+				'{$values['pair']}',
+				'{$values['source']}',
+				'{$values['timestamp']}',
+				'{$values['period']}',
+				'{$values['open']}',
+				'{$values['close']}',
+				'{$values['high']}',
+				'{$values['low']}',
+				'{$values['volume']}',
+				'{$values['imputed']}'
+				)
+			";
+		break;
+
+		# keep the most recent record
+		case 'deduplicate_history':
+			# warning this is inefficient with a large db, better to iterate with $values filter to small number of records
+			$sql = "
+				DELETE a FROM `price_history` a
+				INNER JOIN `price_history` b
+				ON a.pair = b.pair
+				AND a.timestamp = b.timestamp
+				AND a.period = b.period
+				AND a.source = b.source
+				WHERE
+				a.history_id < b.history_id
+				{$values['filterquery']}
+				;
+			";
+		break;
+
+		case 'update_content':
+			$sql = "
+				REPLACE INTO `web_content`
+				(
+				`content_id`,
+				`content`,
+				`timestamp`,
+				`notified`
+				)
+				VALUES
+				(
+				'{$values['content_id']}',
+				'{$values['content']}',
+				'{$values['timestamp']}',
+				'{$values['notified']}'
+				)
+			";
+		break;
+
+		case 'get_content':
+			$sql = "SELECT * FROM `web_content` {$values['filterquery']}";
+		break;
+
+		case 'get_tactics':
+			$sql = "SELECT * FROM `tactics` {$values['filterquery']}";
+		break;
+
+		case 'update_tactic':
+			$sql = "UPDATE `tactics` SET `{$values['field']}` = '{$values['value']}' WHERE `tactic_id` = '{$values['tactic_id']}'";
+		break;
+
+		case 'get_transactions':
+			$sql = "SELECT * FROM `transactions` {$values['filterquery']}";
+		break;
 
 		case 'update_transaction':
-			$sql = "REPLACE INTO `transactions`
-						(
-						`transaction_id`,
-						`investment_id`,
-						`investment_proportion`,
-						`time_opened`,
-						`time_closed`,
-						`capital_amount`,
-						`capital_fee`,
-						`purpose`,
-						`exchange`,
-						`exchange_transaction_id`,
-						`exchange_transaction_status`,
-						`percent_complete`,
-						`pair_asset`,
-						`from_asset`,
-						`from_amount`,
-						`to_asset`,
-						`to_amount`,
-						`to_fee`,
-						`pair_price`,
-						`from_price_usd`,
-						`to_price_usd`,
-						`price_reference`,
-						`fee_amount_usd`,
-						`price_aud_usd`,
-						`aud_usd_reference`,
-						`from_wallet`,
-						`to_wallet`,
-						`tactic_id`,
-						`strategy_result_usd`
-						)
-				VALUES (
-		        '{$values['transaction_id']}',
-		        '{$values['investment_id']}',
-		        '{$values['investment_proportion']}',
-		        '{$values['time_opened']}',
-		        '{$values['time_closed']}',
-		        '{$values['capital_amount']}',
-		        '{$values['capital_fee']}',
-		        '{$values['purpose']}',
-						'{$values['exchange']}',
-						'{$values['exchange_transaction_id']}',
-		        '{$values['exchange_transaction_status']}',
-		        '{$values['percent_complete']}',
-		        '{$values['pair_asset']}',
-						'{$values['from_asset']}',
-						'{$values['from_amount']}',
-						'{$values['to_asset']}',
-						'{$values['to_amount']}',
-						'{$values['to_fee']}',
-		        '{$values['pair_price']}',
-						'{$values['from_price_usd']}',
-						'{$values['to_price_usd']}',
-						'{$values['price_reference']}',
-		        '{$values['fee_amount_usd']}',
-		        '{$values['price_aud_usd']}',
-		        '{$values['aud_usd_reference']}',
-		        '{$values['from_wallet']}',
-		        '{$values['to_wallet']}',
-		        '{$values['tactic_id']}',
-		        '{$values['strategy_result_usd']}'
-						)";
-			break;
-
-    default: // default to assuming that the label IS the query
-        $sql=$querylabel;
-        break;
-
-    }
+			$sql = "
+				REPLACE INTO `transactions`
+				(
+				`transaction_id`,
+				`investment_id`,
+				`investment_proportion`,
+				`time_opened`,
+				`time_closed`,
+				`capital_amount`,
+				`capital_fee`,
+				`purpose`,
+				`exchange`,
+				`exchange_transaction_id`,
+				`exchange_transaction_status`,
+				`percent_complete`,
+				`pair_asset`,
+				`from_asset`,
+				`from_amount`,
+				`to_asset`,
+				`to_amount`,
+				`to_fee`,
+				`pair_price`,
+				`from_price_usd`,
+				`to_price_usd`,
+				`price_reference`,
+				`fee_amount_usd`,
+				`price_aud_usd`,
+				`aud_usd_reference`,
+				`from_wallet`,
+				`to_wallet`,
+				`tactic_id`,
+				`strategy_result_usd`
+				)
+				VALUES
+				(
+				'{$values['transaction_id']}',
+				'{$values['investment_id']}',
+				'{$values['investment_proportion']}',
+				'{$values['time_opened']}',
+				'{$values['time_closed']}',
+				'{$values['capital_amount']}',
+				'{$values['capital_fee']}',
+				'{$values['purpose']}',
+				'{$values['exchange']}',
+				'{$values['exchange_transaction_id']}',
+				'{$values['exchange_transaction_status']}',
+				'{$values['percent_complete']}',
+				'{$values['pair_asset']}',
+				'{$values['from_asset']}',
+				'{$values['from_amount']}',
+				'{$values['to_asset']}',
+				'{$values['to_amount']}',
+				'{$values['to_fee']}',
+				'{$values['pair_price']}',
+				'{$values['from_price_usd']}',
+				'{$values['to_price_usd']}',
+				'{$values['price_reference']}',
+				'{$values['fee_amount_usd']}',
+				'{$values['price_aud_usd']}',
+				'{$values['aud_usd_reference']}',
+				'{$values['from_wallet']}',
+				'{$values['to_wallet']}',
+				'{$values['tactic_id']}',
+				'{$values['strategy_result_usd']}'
+				)
+			";
+		break;
+
+		default: // default to assuming that the label IS the query
+			$sql = $querylabel;
+		break;
+
+	}
+
 	return $sql;
+
 }
 
 function sqlparts($part,$config,$values) {
 
-  if (is_array($values))
-    foreach ($values as $key=>$value)
-        $values[$key] = safeIntoDB($value, $key, $config);
+	if (is_array($values))
+		foreach ($values as $key=>$value)
+			$values[$key] = safeIntoDB($value, $key, $config);
+
+	switch ($part) {
+
+		case "test":
+			$sqlpart = " ";
+		break;
 
-  switch ($part) {
+		default:
+			if ($config['debug_sql']) echo "

Failed to find sql component '$part'

'"; + $sqlpart=$part; + break; - case "test": - $sqlpart = " "; - break; - default: - if ($config['debug_sql']) echo "

Failed to find sql component '$part'

'"; - $sqlpart=$part; - break; - } + } - if ($config['debug_sql']) - echo "
Sqlparts '$part': Result $sqlpart
Sanitised values in sqlparts: ",print_r($values,true),'
'; + if ($config['debug_sql']) + echo + "
Sqlparts '$part': Result $sqlpart
Sanitised values in sqlparts: " . + print_r($values,true) . + "
" + ; - return $sqlpart; + return $sqlpart; } diff --git a/price_history.php b/price_history.php index 2196ca0..3da166b 100644 --- a/price_history.php +++ b/price_history.php @@ -4,7 +4,7 @@ echo '
';
 
 if(isset($_GET['pair_id'])) $pair_id = $_GET['pair_id'];
-	else $pair_id = FALSE;
+else $pair_id = FALSE;
 
 price_history($config, $pair_id);
 
diff --git a/price_recent.php b/price_recent.php
index cfa08c0..cbcb7bb 100644
--- a/price_recent.php
+++ b/price_recent.php
@@ -4,7 +4,7 @@
 echo '
';
 
 if(isset($_GET['pair_id'])) $pair_id = $_GET['pair_id'];
-	else $pair_id = FALSE;
+else $pair_id = FALSE;
 
 price_recent($config, $pair_id);
 
diff --git a/system_metrics.php b/system_metrics.php
index 376e474..daa1aaa 100644
--- a/system_metrics.php
+++ b/system_metrics.php
@@ -1,4 +1,9 @@
 ' . PHP_EOL . 'query took ' .
-    round((milliseconds() - $config['timestamp']) / 1000, 2) . ' seconds';
+echo
+	'
' .
+	PHP_EOL .
+	'query took ' .
+  round((milliseconds() - $config['timestamp']) / 1000, 2) .
+	' seconds'
+;
diff --git a/technical_analysis.php b/technical_analysis.php
index d20df30..edfc845 100644
--- a/technical_analysis.php
+++ b/technical_analysis.php
@@ -6,8 +6,8 @@
 
 echo '
';
 
-if(isset($_GET['pair_id'])) $pair_id = $_GET['pair_id'];
-	else $pair_id = FALSE;
+if (isset($_GET['pair_id'])) $pair_id = $_GET['pair_id'];
+else $pair_id = FALSE;
 
 technical_analysis($config, $pair_id);
 
@@ -15,106 +15,108 @@
 
 /*
 
-	# ignore all following code
-
-	
-    $values['filterquery'] = " WHERE pair = '" . $pair . "'
-                                AND source = '" . $source . "'
-                                AND period = '" . $period_txt . "'
-                                AND timestamp >= " . $start . "
-                                AND timestamp <= " . $stop;
-    $history = query('select_history', $config, $values);
-
-    echo 'pair: ' . $pair . '
'; - echo 'source: ' . $source . '
'; - echo 'period: ' . $period . '

'; - echo 'observations: ' . count($history). '
'; - - usort($history, function($a, $b) { - return $a['timestamp'] - $b['timestamp']; - }); - - $last = $history[0]['timestamp'] - $diff; - $missing_data = FALSE; - $i = 0; - foreach ($history as $hist) { - $diff_obs = $hist['timestamp'] - $last; - if ($diff !== $diff_obs) { - $missing_data = TRUE; - $missing_obs = $hist['timestamp'] - $diff; - $missing_array = $i; - } - $last = $hist['timestamp']; - $i++; - } - if($missing_data) { - echo 'missing data at array position ' . $missing_array . ',
time ' . date('Y-m-d H:i T', $missing_obs / 1000) . ',
timestamp ' . $missing_obs . ',
period ' . $diff . '
'; - var_dump($history[$missing_array - 1]); - var_dump($history[$missing_array]); - } - $data_open = array_column($history, 'open'); - $data_high = array_column($history, 'high'); - $data_low = array_column($history, 'low'); - $data_close = array_column($history, 'close'); - $data_volume = array_column($history, 'volume'); - - $values['filterquery'] = " WHERE class = 'candlestick'"; - $indicators = query('select_indicators', $config, $values); - - foreach ($indicators as $indicator) { - $result = $indicator['function']($data_open, $data_high, $data_low, $data_close); - #if(end($result)) echo $indicator['description'] . ': ' . end($result) . '
'; - if ($indicator['reliability']) - for ($i = count($result) - 5; $i <= count($result); $i++) { - if($result[$i]) { - echo $i . ' ' . $indicator['description'] . ': ' . $result[$i] . ', '; - echo $indicator['indication'] . ', ' . $indicator['reliability'] . '
'; - } - } - } - - $result = trader_ema($data_close, 12); - echo 'ema 12: ' . end($result); - if (end($data_close) > end($result)) { - echo ' above
'; - } else { - echo ' below
'; - } - - $result = trader_ema($data_close, 50); - echo 'ema 50: ' . end($result) . '
'; - - $result = trader_ema($data_close, 200); - echo 'ema 200: ' . end($result) . '
'; - - $result = trader_rsi($data_close, 14); - echo 'rsi 14: ' . end($result) . '
'; - - $result = trader_rsi($data_close, 24); - echo 'rsi 24: ' . end($result) . '
'; - - $last = count($history); - $history_recent = array(); - $volume_recent = array(); - for ($i = $last - $points; $i < $last; $i++) { - array_push($history_recent, array( - $history[$i]['timestamp'], - $history[$i]['open'], - $history[$i]['high'], - $history[$i]['low'], - $history[$i]['close'] - )); - array_push($volume_recent, array( - $history[$i]['timestamp'], - (int)$history[$i]['volume'] - )); - } - #var_dump($history_recent); - echo '
from ' . date('Y-m-d H:i T', $history_recent[$points - 1][0] / 1000); - echo ' to ' . date('Y-m-d H:i T', $history_recent[0][0] / 1000) . '
'; - echo $points . ' observations'; - - ?> +# ignore all following code + + +$values['filterquery'] = " + WHERE pair = '" . $pair . "' + AND source = '" . $source . "' + AND period = '" . $period_txt . "' + AND timestamp >= " . $start . " + AND timestamp <= " . $stop +; +$history = query('select_history', $config, $values); + +echo 'pair: ' . $pair . '
'; +echo 'source: ' . $source . '
'; +echo 'period: ' . $period . '

'; +echo 'observations: ' . count($history). '
'; + +usort($history, function($a, $b) { + return $a['timestamp'] - $b['timestamp']; +}); + +$last = $history[0]['timestamp'] - $diff; +$missing_data = FALSE; +$i = 0; +foreach ($history as $hist) { + $diff_obs = $hist['timestamp'] - $last; + if ($diff !== $diff_obs) { + $missing_data = TRUE; + $missing_obs = $hist['timestamp'] - $diff; + $missing_array = $i; + } + $last = $hist['timestamp']; + $i++; +} +if ($missing_data) { + echo 'missing data at array position ' . $missing_array . ',
time ' . date('Y-m-d H:i T', $missing_obs / 1000) . ',
timestamp ' . $missing_obs . ',
period ' . $diff . '
'; + var_dump($history[$missing_array - 1]); + var_dump($history[$missing_array]); +} +$data_open = array_column($history, 'open'); +$data_high = array_column($history, 'high'); +$data_low = array_column($history, 'low'); +$data_close = array_column($history, 'close'); +$data_volume = array_column($history, 'volume'); + +$values['filterquery'] = " WHERE class = 'candlestick'"; +$indicators = query('select_indicators', $config, $values); + +foreach ($indicators as $indicator) { + $result = $indicator['function']($data_open, $data_high, $data_low, $data_close); + #if (end($result)) echo $indicator['description'] . ': ' . end($result) . '
'; + if ($indicator['reliability']) + for ($i = count($result) - 5; $i <= count($result); $i++) { + if ($result[$i]) { + echo $i . ' ' . $indicator['description'] . ': ' . $result[$i] . ', '; + echo $indicator['indication'] . ', ' . $indicator['reliability'] . '
'; + } + } +} + +$result = trader_ema($data_close, 12); +echo 'ema 12: ' . end($result); +if (end($data_close) > end($result)) { + echo ' above
'; +} else { + echo ' below
'; +} + +$result = trader_ema($data_close, 50); +echo 'ema 50: ' . end($result) . '
'; + +$result = trader_ema($data_close, 200); +echo 'ema 200: ' . end($result) . '
'; + +$result = trader_rsi($data_close, 14); +echo 'rsi 14: ' . end($result) . '
'; + +$result = trader_rsi($data_close, 24); +echo 'rsi 24: ' . end($result) . '
'; + +$last = count($history); +$history_recent = array(); +$volume_recent = array(); +for ($i = $last - $points; $i < $last; $i++) { + array_push($history_recent, array( + $history[$i]['timestamp'], + $history[$i]['open'], + $history[$i]['high'], + $history[$i]['low'], + $history[$i]['close'] + )); + array_push($volume_recent, array( + $history[$i]['timestamp'], + (int)$history[$i]['volume'] + )); +} +#var_dump($history_recent); +echo '
from ' . date('Y-m-d H:i T', $history_recent[$points - 1][0] / 1000); +echo ' to ' . date('Y-m-d H:i T', $history_recent[0][0] / 1000) . '
'; +echo $points . ' observations'; + +?> @@ -130,82 +132,82 @@ --> -
+
+
- +